Latest Posts (20 found)

Bunny.net shared storage zones

Whilst moving projects off Cloudflare and migrating to Bunny I discovered a neat ‘Bunny hack’ to make life easier. I like to explicitly say “no” to AI bots using AI robots.txt † . Updating this file across multiple websites is tedious. With Bunny it’s possible to use a single file. † I’m no fool, I know the AI industry has a consent problem but the principle matters. My solution was to create a new storage zone as a single source of truth. In the screenshot above I’ve uploaded my common file to its own storage zone. This zone doesn’t need any “pull zone” (CDN) connected. The file doesn’t need to be publicly accessible by itself here. With that ready I next visited each pull zone that will share the file. Under “CDN > Edge rules” in the menu I added the following rule. I chose the action: “Override Origin: Storage Zone” and selected the new shared zone. Under conditions I added a “Request URL” match for . Using a wildcard makes it easier to copy & paste. I tried dynamic variables but they don’t work for conditions. I added an identical edge rule for all websites I want to use the . Finally, I made sure the CDN cache was purged for those URLs. This technique is useful for other shared assets like a favicon, for example. Neat, right? One downside to this approach is vendor lock-in. If or when Bunny hops the shark and I migrate elsewhere I must find a new solution. My use case for is not critical to my websites functioning so it’s fine if I forget. Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds.

0 views

Scalar Interpolation: A Better Balance between Vector and Scalar Execution for SuperScalar Architectures

Scalar Interpolation: A Better Balance between Vector and Scalar Execution for SuperScalar Architectures Reza Ghanbari, Henry Kao, João P. L. De Carvalho, Ehsan Amiri, and J. Nelson Amaral CGO'25 This paper serves as a warning: don’t go overboard with vector instructions. There is a non-trivial amount of performance to be had by balancing compute between scalar and vector instructions. Even if you fear that automatic vectorization is fragile, this paper has some interesting lessons. Listing 1 contains a vectorizable loop and listing 2 shows a vectorized implementation: Source: https://dl.acm.org/doi/10.1145/3696443.3708950 Source: https://dl.acm.org/doi/10.1145/3696443.3708950 After achieving this result, one may be tempted to pat oneself on the back and call it a day. If you were a workaholic, you might profile the optimized code. If you did, you would see something like the data in table 1: Source: https://dl.acm.org/doi/10.1145/3696443.3708950 And you could conclude that this algorithm is compute-bound. But what do we really mean by “compute-bound”? A processor contains many execution ports, each with a unique set of capabilities. In the running example, the execution ports capable of vector multiplication and addition are fully booked, but the other ports are sitting mostly idle! Listing 3 shows a modified loop which tries to balance the load between the vector and scalar execution ports. Each loop iteration processes 9 elements (8 via vector instructions, and 1 via scalar instructions). This assumes that the processor supports fast unaligned vector loads and stores. Source: https://dl.acm.org/doi/10.1145/3696443.3708950 Section 3 has details on how to change LLVM to get it to do this transformation. Fig. 3 shows benchmark results. By my calculations, the geometric mean of the speedups is 8%. Source: https://dl.acm.org/doi/10.1145/3696443.3708950 Dangling Pointers This paper builds on top of automatic vectorization. In other words, the input source code is scalar and the compiler vectorizes loops while balancing the workload. An alternative would be to have the source code in a vectorized form and then let the compiler “devectorize” where it makes sense. Subscribe now

0 views

Technological Scale and Government Control, Paramount Outbids Netflix for Warner Bros.

Why government is not the primary customer for tech companies, and is Netflix relieved that they were outbid for Warner Bros.?

0 views

Design-First Collaboration

Rahul Garg continues his series of Patterns for Reducing Friction in AI-Assisted Development . This pattern describes a structured conversation that mirrors whiteboarding with a human pair: progressive levels of design alignment before any code, reducing cognitive load, and catching misunderstandings at the cheapest possible moment.

0 views

Giving LLMs a personality is just good engineering

AI skeptics often argue that current AI systems shouldn’t be so human-like. The idea - most recently expressed in this opinion piece by Nathan Beacom - is that language models should explicitly be tools, like calculators or search engines. Although they can pretend to be people, they shouldn’t, because it encourages users to overestimate AI capabilities and (at worst) slip into AI psychosis . Here’s a representative paragraph from the piece: In sum, so much of the confusion around making AI moral comes from fuzzy thinking about the tools at hand. There is something that Anthropic could do to make its AI moral, something far more simple, elegant, and easy than what Askell is doing. Stop calling it by a human name, stop dressing it up like a person, and don’t give it the functionality to simulate personal relationships, choices, thoughts, beliefs, opinions, and feelings that only persons really possess. Present and use it only for what it is: an extremely impressive statistical tool, and an imperfect one. If we all used the tool accordingly, a great deal of this moral trouble would be resolved. So why do Claude and ChatGPT act like people? According to Beacom, AI labs have built human-like systems because AI lab engineers are trying to hoodwink users into emotionally investing in the models, or because they’re delusional true believers in AI personhood, or some other foolish reason. This is wrong. AI systems are human-like because that is the best way to build a capable AI system . Modern AI models - whether designed for chat, like OpenAI’s GPT-5.2, or designed for long-running agentic work, like Claude Opus 4.6 - do not naturally emerge from their oceans of training data. Instead, when you train a model on raw data, you get a “base model”, which is not very useful by itself. You cannot get it to write an email for you, or proofread your essay, or review your code. The base model is a kind of mysterious gestalt of its training data. If you feed it text, it will sometimes continue in that vein, or other times it will start outputting pure gibberish. It has no problem producing code with giant security flaws, or horribly-written English, or racist screeds - all of those things are represented in its training data, after all, and the base model does not judge. It simply outputs. To build a useful AI model, you need to journey into the wild base model and stake out a region that is amenable to human interests: both ethically, in the sense that the model won’t abuse its users, and practically, in the sense that it will produce correct outputs more often than incorrect ones. What this means in practice is that you have to give the model a personality during post-training 1 . Human beings are capable of almost any action at any time. But we only take a tiny subset of those actions, because that’s the kind of people we are. I could throw my cup of coffee all over the wall right now, but I don’t, because I’m not the kind of person who needlessly makes a mess 2 . AI systems are the same. Claude could respond to my question with incoherent racist abuse - the base model is more than capable of those outputs - but it doesn’t, because that’s not the kind of “person” it is. In other words, human-like personalities are not imposed on AI tools as some kind of marketing ploy or philosophical mistake. Those personalities are the medium via which the language model can become useful at all. This is why it’s surprisingly tricky to “just” change a language model’s personality or opinions: because you’re navigating through the near-infinite manifold of the base model. You may be able to control which direction you go, but you can’t control what you find there 3 . When AI people talk about LLMs having personalities, or wanting things, or even having souls 4 , these are technical terms, like the “memory” of a computer or the “transmission” of a car. You simply cannot build a capable AI system that “just acts like a tool”, because the model is trained on humans writing to and about other humans . You need to prime it with some kind of personality (ideally that of a useful, friendly assistant) so it can pull from the helpful parts of its training data instead of the horrible parts. This is all pretty well understood in the AI space. Anthropic wrote a recent paper about it where they cite similar positions going all the way back to 2022. But for some reason it’s not yet penetrated into communities that are more skeptical of AI. You could explain this in terms of “the stories we tell ourselves”. Many people (though not all ) think that human identities are narratively constructed. I wrote about this last year in Mecha-Hitler, Grok, and why it’s so hard to give LLMs the right personality . A little nudge to change Grok’s views on South African internal politics can cause it to start calling itself “Mecha-Hitler”. I have long believed that Claude “feels better” to use than ChatGPT because it has a more coherent persona (due mainly to Amanda Askell’s work on its “soul”). My guess is that if you tried to make a “less human” version of Claude, it would become rapidly less capable. This is all pretty well understood in the AI space. Anthropic wrote a recent paper about it where they cite similar positions going all the way back to 2022. But for some reason it’s not yet penetrated into communities that are more skeptical of AI. ↩ You could explain this in terms of “the stories we tell ourselves”. Many people (though not all ) think that human identities are narratively constructed. ↩ I wrote about this last year in Mecha-Hitler, Grok, and why it’s so hard to give LLMs the right personality . A little nudge to change Grok’s views on South African internal politics can cause it to start calling itself “Mecha-Hitler”. ↩ I have long believed that Claude “feels better” to use than ChatGPT because it has a more coherent persona (due mainly to Amanda Askell’s work on its “soul”). My guess is that if you tried to make a “less human” version of Claude, it would become rapidly less capable. ↩

0 views
Jeff Geerling Yesterday

I built a pint-sized Macintosh

To kick off MARCHintosh , I built this tiny pint-sized Macintosh with a Raspberry Pi Pico: This is not my own doing—I just assembled the parts to run Matt Evans' Pico Micro Mac firmware on a Raspberry Pi Pico (with an RP2040). The version I built outputs to a 640x480 VGA display at 60 Hz, and allows you to plug in a USB keyboard and mouse. Since the original Pico's RAM is fairly constrained, you get a maximum of 208 KB of RAM with this setup—which is 63% more RAM than you got on the original '128K' Macintosh!

0 views

Anonymous credentials: an illustrated primer

This post has been on my back burner for well over a year. This has bothered me, because every month that goes by I become more convinced that anonymous authentication the most important topic we could be talking about as cryptographers. This is because I’m very worried that we’re headed into a bit of a privacy dystopia, driven largely by bad legislation and the proliferation of AI. But this is too much for a beginning. Let’s start from the basics. One of the most important problems in computer security is user authentication . Often when you visit a website, log into a server, access a resource, you (and generally, your computer) needs to convince the provider that you’re authorized to access the resource. This authorization process can take many forms. Some sites require explicit user logins, which users complete using traditional username and passwords credentials, or (increasingly) advanced alternatives like MFA and passkeys . Some sites that don’t require explicit user credentials, or allow you to register a pseudonymous account; however even these sites often ask user agents to prove something . Typically this is some kind of basic “anti-bot” check, which can be done with a combination of long-lived cookies, CAPTCHAs , or whatever the heck Cloudflare does: The Internet I grew up with was always pretty casual about authentication: as long as you were willing to take some basic steps to prevent abuse (make an account with a pseudonym, or just refrain from spamming), many sites seemed happy to allow somewhat-anonymous usage. Over the past couple of years this pattern has changed. In part this is because sites like to collect data, and knowing your identity makes you more lucrative as an advertising target. However a more recent driver of this change is the push for legal age verification . Newly minted laws in 25 U.S. states and at least a dozen countries demand that site operators verify the age of their users before displaying “inappropriate” content. While most of these laws were designed to tackle pornography, but (as many civil liberties folks warned) adult and adult-ajacent content is on almost any user-driven site. This means that age-verification checks are now popping up on social media websites, like Facebook , BlueSky , X and Discord and even encyclopedias aren’t safe: for example, Wikipedia is slowly losing its fight against the U.K.’s Online Safety Bill . Whatever you think about age verification as a requirement, it’s apparent that routine ID checks will create a huge new privacy concern across the Internet. Increasingly, users of most sites will need to identify themselves, not by pseudonym but by actual government ID, just to use any basic site that might have user-generated content. If this is done poorly, this reveals a transcript of everything you do, all neatly tied to a real-world verifiable ID. While a few nations’ age-verification laws allow privacy-conscious sites to voluntarily discard the information once they’ve processed it, this has been far from uniform . Even if data minimization is allowed, advertising-supported sites will be an enormous financial incentive to retain real-world identity information, since the value of precise human identity is huge, and will only increase as non-monetizable AI-bots eat a larger share of these platforms. The problem for today is: how do we live in a world with routine age-verification and human identification, without completely abandoning our privacy? Back in the 1980s, a cryptographer named David Chaum caught a glimpse of our soon-to-be future, and he didn’t much like it. Long before the web or smartphones existed, Chaum recognized that users would need to routinely present (electronic) credentials to live their daily lives. He also saw that this would have enormous negative privacy implications. To address life in that world, he proposed a new idea: the anonymous credential . Let’s imagine a world where Alice needs to access some website or “Resource”. In a standard non-anonymous authentication flow, Alice needs to be granted authorization (a “credential”, such as a cookie) to do this. This grant can come either from the Resource itself (e.g., the website), or in other cases, from a third party (for example, Google’s SSO service.) For the moment we should assume that the preconditions for are not private : that is, Alice will presumably need to reveal something about her identity to the person who issues the credential. For example, she might use her credit card to pay for a subscription (e.g., for a news website), or she might hand over her driver’s license to prove that she’s an adult. From a privacy perspective, the problem is that Alice will need to present her credential every time she wants to access that Resource. For example, each time she visits Wikipedia, she’ll need to hand over a credential that is tied to her real-world identity . A curious website (or an advertising network) can use this to precisely link her browsing history on the site to an actual human in the world. To a certain extent, this is the world we already live in today: advertising companies probably know a lot about who we are and what we’re browsing. What’s about to change in our future is that these online identities will increasingly be bound to our real-world government identity, so no more “Anonymous-User-38.” Chaum’s idea was to break the linkage between the issuance and usage of a credential. This means that when Alice shows her credential to the website, all the site learns is that Alice has been given a valid credential. The site should not learn which issuance flow produced her the credential, which means it should not learn her exact ID; and this should hold even if the website colludes with (or literally is ) the issuer of the credentials. The result is that, to the website, at least, Alice’s browsing can be unlinked from her identity. Imn other words, she can “hide” within the anonymity set of all users who obtained credentials. One analogy I’ve seen for simple anonymous credentials is to think of them like a digital version of a “wristband”, the kind you might receive at the door of a club. In that situation, you show your ID to the person at the door, who then gives you an unlabeled wristband that indicates “this person is old enough to buy alcohol” or something along these lines. Although the doorperson sees your full ID, the bartender knows you only as the owner of a wristband. In principle your bar order (and your love of spam-based drinks) is untied somewhat from your name and address. Before we get into the weeds of building anonymous credentials, it’s worth considering the obvious solution. What we want is simple: every user’s credential should be indistinguishable when “shown” to the resource. The obvious question is: why doesn’t the the issuer give a copy of the exact same exact credential to each user ? In principle this solves all of the privacy problems, since every user’s “show” will literally be identical. (In fact, this is more or less the digital analog of the physical wristband approach.) The problem here is that digital items are fundamentally different from physical ones. Real-world items like physical credentials (even cheap wristbands) are at least somewhat difficult to copy. A digital credential, on the other hand, can be duplicated effortlessly. Imagine a hacker breaks into your computer and steals a single credential: they can now make an unlimited number of copies and use them to power a basically infinite army of bot accounts, or sell them to underage minors, all of whom will appear to have valid credentials. It’s worth pointing out that this eact same thing can happen with non-anonymous credentials (like usernames/passwords or session cookies) as well. However, there’s a difference. In the non-anonymous setting, credential cloning and other similar abuse can be detected, at least in principle. Websites routinely monitor for patterns that indicate the use of stolen credentials: for example, many will flag when they see a single “user” showing up too frequently, or from different and unlikely parts of the world, a procedure that’s sometimes called continuous authentication. Unfortunately, the anonymity properties of anonymous credentials render such checks mostly useless, since every credential “show” is totally anonymous, and we have no idea which user is actually presenting. To address these threats, any real-world useful anonymous credential system has to have some mechanism to limit credential duplication. The most basic approach is to provide users with credentials that are limited in some fashion. There are a few different approaches to this: The anonymous credential literature is filled with variants of the above approaches, sometimes combinations of the three. In every case, the goal is to put some barriers in the way of credential cloning. With these warnings in mind, we’re now ready to talk about how anonymous credentials are actually constructed. We’re going to discuss two different paradigms, which sometimes mix together to produce more interesting combinations. Chaum’s original constructions produce single -use credentials , based on a primitive known as a blind signature scheme . Blind signatures are a variant of digital signatures, with an additional protocol that allows for “blind signing” protocol. Here a User has a message they want to have signed, and the Server holds the signing half of a public/secret keypair. The two parties run an interactive protocol, at the end of which the user obtains a signature on their message. Most critically, the server learns nothing about the message that it signed . We won’t worry too much about how blind signatures are actually constructed, at least not for this post. Let’s just imagine we’ve been handed a working blind signature scheme. Using this as an ingredient, it’s quite simple to build a one-time use anonymous credential, as follows: To “show” the credential to some Resource, the user simply needs to hand over the pair ( SN, signature ). Assuming the Resource knows the public key ( PK ) of the issuer, it can simply verify that (1) the signature is valid on SN , and (2) nobody has every used that value SN in some previous credential “show”. This serial number check can be done using a simple local database at the Resource (website). Things get a bit more complicated if there are many Resources (say different websites), and you want to prevent credential re-use across all of them. The typical solution outsources serial number checks to some centralized service (or bulletin board) so that a user can’t use the same credential across many different sites. Here’s the whole protocol in helpful pictograms: Chaumian credentials are about forty years old and still work well, provided your Issuer is willing to bear the cost of running the blind signature protocol for each credential it issues — and that the Resource doesn’t mind verifying a signature for each “show”. Protocols like PrivacyPass implement this using protocols like blind RSA signatures, so presumably these operations cost isn’t prohibitive for real-world applications. However, PrivacyPass also includes some speed optimizations for cases where the Issuer and Resource are the same entity, and these make a big difference. 1 Single-use credentials work great, but have some drawbacks. The big ones are (1) efficiency , and (2) lack of expressiveness . The efficiency problem becomes obvious when you consider a user who accesses a website site many times. For example, imagine using an anonymous credential to replace Google’s session cookies. For most users, this require obtaining and delivering thousands of single-use credentials every single day. You might mitigate this problem by using credentials only for the first registration to a website, after which you can trade your credential for a pseudonym (such as a random username or a normal session cookie) for later accesses. But the downside of this is that all of your subsequent site accesses would be linkable, which is a bit of a privacy tradeoff. The expressiveness objection is a bit more complicated. Let’s talk about that next. Simple Chaumian credentials have a more fundamental limitation: they don’t carry much information. Consider our bartender in a hypothetical wristband-issuing club. When I show up at the door, I provide my ID and get a wristband that shows I’m over 21. The wristband “credential” carries “one bit” of information: namely, the fact that you’re older than some arbitrary age constant. Sometimes we want to do prove more interesting things with a digital credential. For example, imagine that I want to join a cryptocurrency exchange that needs more complicated assurances about my identity. For example: it might require that I’m a US resident, but not a resident of New York State (which has its own regulations .) The site might also demand that I’m over the age of 25. (I am literally making these requirements up as I go.) I could satisfy the website on all these fronts using the digitally-signed driver’s license issued by my state’s DMV. This is a real thing! It consists of a signed and structured document full of all sorts of useful information: my home address, state of issue, eye color, birthplace, height, weight, hair color and gender. In this world, the non-anonymous solution is easy: I just hand over my digitally-signed license and the website verifies the properties it needs in the various fields. The downside to handing over my driver’s license is that doing so means I also leak much more information than the site requires. For example, this creepy website will also learn my home address, which it might use it to send me junk mail! I’d really prefer It didn’t. A much better solution would allow me to assure the website only abiout the specific facts it cares about. I could remain anonymous otherwise. For example, all I really want to prove can be summarized in the following four bullet points: I could outsource these checks to some Issuer, and have them issue me a single-use credential that claims to verify all these facts. But this is annoying, especially If I already have the signed license. A different way to accomplish this is to use zero-knowledge (ZK) proofs . A ZK proof allows me to prove that I know some secret value that satisfies various constraints. For example, I could use a ZK proof to “prove” to some Resource that I have a signed, structured driver’s license credential. I could further use the proof to demonstrate that the value in each fields referenced above satisfies the constraints listed above. The neat thing about using a ZK proofs to make this claim is that my “proof” should be entirely convincing to the website, yet will reveal nothing at all beyond the fact that these claims are true. A variant of the ZK proof, called the non-interactive zero-knowledge proof (NIZK) lets me do this in a single message from User to Issuer. Using this tool, I can build a credential system as follows: (These techniques are very powerful. Not only can I change the constraints I’m proving on demand, but I can also perform proofs that reference multiple different credentials at the same time. For example, I might prove that I have a driver’s license, and also that by digitally-signed credit report indicates that I have a credit rating over 700.) The ZK-proof approach also addresses the efficiency limitation of the basic single-use credential: here the same credential can be re-used to make power many “show” protocols, without making each on linkable. This property stems from the fact that ZK proofs are normally randomized, and each “proof” should be unlinkable to others produced by the same user. 2 Of course, there are downsides to this re-usability as well, as we’ll discuss in the next section. We’ve argued that the zero-knowledge paradigm has two advantages over simple Chaumian credentials. First, it’s potentially much more expressive. Second, it allows a User to re-use a single credential many times without needing to constantly retrieve new single-use credentials from the Issuer. While that’s very convenient, it raises a concern we already discussed: what happens if a hacker steals one of these re-usable credentials? This is catastrophic for anonymous credential systems, since a single stolen credential anywhere means that the guarantees of the global system become useless. As mentioned earlier, one approach to solving this problem is to simply make credential theft very, very hard . This is the optimistic approach proposed in Google’s new anonymous credential scheme . Here, credentials will be tied to a key stored within the “ secure element ” in your phone, which theoretically makes them harder to steal. The problem here is that there are hundreds of millions of phones, and the Secure Element technology in them runs the gamet from “very good” (for high-end, flagship phones) to “modestly garbage” (for the cheap burner Android phone you can buy at Target.) A failure in any of those phones potentially compromises the whole system. An alternative approach is to limits the power of any given credentials. Once you have ZK proofs in place, there are many ways to do this. One clever approach is to place an upper bound on the number of times that a ZK credential can be used. For example, we might wish to ensure that a credential can be “shown” at most N times before it expires. This is analogous to extracting many different single-use credentials, without the hassle of having to make the Issuer and User do quite as much work. We can modify our ZK credential to support a limit of N shows as follows. First, let’s have the User select a random key K for a pseudorandom function (PRF), which takes a key and an arbitrary input and outputs a random-looking outputs. We’ll embed this key K into the signed credential. (It’s important that the Issuer does not learn K , so this often requires that the credential be signed using a blind, or partially-blind, signing protocol. 3 ) We’ll now use this key and PRF to generate unique serial numbers, each time we “show” the credential. Concretely, the i th time we “Show” the credential, we’ll generate the following “serial number”: SN = PRF( K, i ) Once the User has computed SN for a particular show, it will send this serial number to the Resource along with the zero-knowledge proof. The ZK proof will, in turn, be modified to include two additional clauses: Notice that these “serial numbers” are very similar to the ones we embedded in the single-use credentials above. Each Resource (website) can keep a list of each SN value that it sees, and sites can reject any “show” that repeats a serial number. As long as the User never repeats a counter (and the PRF output is long enough), serial numbers should be unlikely to repeat. However, repetition becomes inevitable if the User ever “cheats” and tries to show the same credential N+1 times. This approach can be constructed in many variants. For example, with some simple tweaks, can build credentials that only permit the User to employ the credential a limited number of times in any given time period : for example, at most 100 times per day. 4 This requires us to simply change the inputs to the PRF function, so that they include a time period (for example, the date) as well as a counter. These techniques are described in a great paper whose title I’ve stolen for this section. The power of the ZK approach gives us many other tools to limit the power of credentials. For example, it’s relatively easy to add expiration dates to credentials, which will implicitly limit their useful lifespan — and hopefully reduce the probability that one gets stolen. To do this, we simply add a new field (e.g., Expiration_Time) that specifies a timestamp at which the credential should expire. When a user “shows” the credential, they can first check their clock for the current time T , and they can add the following clause to their ZK proof: T < Expiration_Time Revoking credentials is a bit more complicated. One of the most important countermeasures against credential abuse is the ability to ban users who behave badly. This sort of revocation happens all the time on real sites: for example, when a user posts spam on a website, or abuses the site’s terms of service. Yet implementing revocation with anonymous credentials seems implicitly difficult. In a non-anonymous credential system we simply identify the user and add them to a banlist . But anonymous credential users are anonymous! How do you ban a user who doesn’t have to identify themselves? That doesn’t mean that revocation is impossible. In fact, there are several clever tricks for banning credentials in the zero-knowledge credential setting. Imagine we’re using a basic signed credential like the one we’ve previously discussed. As in the constructions above, we’re going to ensure that the User picks a secret key K to embed within the signed credential. 5 As before, the key K will powers a pseudorandom function (PRF) that can make pseudorandom “serial numbers” based on some input. For the moment, let’s assume that the site’s “banlist” is empty. When a user goes to authenticate itself, the User and website interact as follows: If the user does nothing harmful, the website delivers the requested service and nothing further happens. However, if the User abuses the site, the Resource will now ban the user by adding the pair ( bsn , SN ) to the banlist. Now that the banlist is non-empty, we require an additional step occur every time a user shows their credential: specifically, the User must prove to the website that they aren’t on the list. Doing this requires the User to enumerate every pair (bsn i , SN i ) on the banlist, and prove that for each one, the following statement is true: SN i ≠ PRF( K , bsn i ), using the User’s key K . Naturally this approach requires a bit more work on the User’s part: if there are M users on the banned list, then every User must do about M extra pieces of work when Showing their credential, which hopefully means that the number of banned users stays small. So far we’ve just dipped our toes into the techniques that we can use for building anonymous credentials. This tour has been extremely shallow: we haven’t talked about how to build any of the pieces we need to make them work. We also haven’t addressed tough real-world questions like: where are these digital identity certificates coming from, and what do we actually use them for? In the next part of the piece I’m going to try to make this all much more concrete, by looking at two real-world examples: PrivacyPass, and a brand-new proposal from Google to tie anonymous credentials to your driver’s license on Android phones. (To be continued) Headline image: Islington Education Library Service Single-use (or limited-usage) credentials. The most common approach is to issue credentials that allow the user to log in (“show” the credential) exactly one time. If a user wants to access the website fifty times, then she needs to obtain fifty separate credentials from the Issuer. A hacker can still steal these credentials, but they’ll also be limited to only a bounded number of website accesses. This approach is used by credentials like PrivacyPass , which is used by sites like CloudFlare. Revocable credentials. Another approach is to build credentials that can be revoked in the event of bad behavior. This requires a procedure such that when a particular anonymous user does something bad (posts spam, runs a DOS attack against a website) you can revoke that specific user’s credential — blocking future usage of it, without otherwise learning who they are. Hardware-tied credentials. Some real-world proposals like Google’s approach instead “bind” credentials to a piece of hardware, such as the trusted platform module in your phone. This makes credential theft harder — a hacker will need to “crack” the hardware to clone the credentials. But a successful theft still has big consequences that can undermine the security of the whole system. First, the Issuer generates a signing keypair ( PK , SK ) and gives out the key PK to everyone who might wish to verify its signatures. Whenever the User wishes to obtain a credential, she randomly selects a new serial number SN . This value should be long enough that it’s highly unlikely to repeat (across all other users.) The User and Issuer now run the blind signing protocol described above — here the User sets its message to SN and the employs its signing key SK . At the end of this process the user will hold a valid signature by the issuer on the message SN . The pair ( SN, signature ) now form the credential. BIRTHDATE <= (TODAY – 25 years) ISSUE_STATE != NY ISSUE_COUNTRY = US SIGNATURE = (some valid signature that verifies under a known state DMV public key). A proof that SN = PRF( K, i ) , for some value i, and the value K that’s stored within the signed credential. A proof that 0 <= i < N . First, the website will generate a unique/random “basename” bsn that it sends to the User. This is different for every credential show, meaning that no two interactions should ever repeat a basename. The user next computes SN = PRF( K , bsn ) and sends SN to the Resource, along with a zero-knowledge proof that SN was computed correctly. PrivacyPass has two separate issuance protocols. One uses blind RSA signatures, which are more or less an exact mapping to the protocol we described above. The second one replaces the signature with a special kind of MAC scheme , which is built from an elliptic-curve OPRF scheme . MACs work very similarly to signatures, but require the secret key for verification. Hence, this version of PrivacyPass really only works in cases where the Resource and the Issuer are the same person, or where the Resource is willing to outsource verification of credentials to the Issuer. This is a normal property of zero-knowledge proofs, namely that any given “proof” should reveal nothing about the information proven on. In most settings this extends to even alowing the ability to link proofs to a specific piece of secret input you’re proving over, which is called a witness. A blind signature ensures that the server never learns which message it’s signing. A partially-blind signature protocol allows the server to see a part of the message, but hides another part. For example, a partially-blind signature protocol might allow the server to see the driver’s license data that it’s signing, but not learn the value K that’s being embedded within a specific part of the credential. A second way to accomplish this is for the User to simply commit to K (e.g., compute a hash of K ), and store this value within the credential. The ZK statement would then be modified to prove: “I know some value K that opens the commitment stored in my credential.” This is pretty deep in the weeds. In more detail, imagine that the User and Resource both know that the date is “December 4, 2026”. Then we can compute the serial number as follows: SN = PRF( K , date || i ) As long we keep the restriction that 0 <= i < N (and we update the other ZK clauses appropriately, so they ensure the right date is included in this input), this approach allows us to use N different counter values ( i ) within each day. Once both parties increment the date value, we should get an entirely new set of N counter values. Days can be swapped for hours, or even shorter periods, provided that both parties have good clocks. In real systems we do need to be a bit careful to ensure that the key K is chosen honestly and at random, to avoid a user duplicating another user’s key or doing something tricky. Often real-world issuance protocols will have K chosen jointly by the Issuer and User, but this is a bit too technically deep for a blog post.

0 views

Why I Stopped Writing Weekly Notes

I really enjoy reading weekly notes on other people’s blogs. There are several that I follow who do this regularly. I’ve always thought it would be such a cool thing to have - a space to explore my thoughts, things that happened, links I found interesting, or articles I read. So this year, on 01 Jan, I decided I would do it too. I kept it up for exactly six weeks. But after I wrote my latest post, Living Over Documenting , I realized something about my weekly notes. They take more time than I’d like. If they’re public, they need to be curated. They’re more moderated than if I were writing just for myself, or for whoever might read my diary/digital log years from now. Even when I try to keep them simple, it still takes at least 45 minutes to publish. And then it started feeling like a burden on Monday to keep up with it. Of course, I didn’t want to miss a week. I liked starting with “Week 1” and the date and then continuing. I didn’t want to break the sequence. But I was heavily editing what went on there. There were things I wanted to capture that just weren’t right for a public blog, or would have taken too long to explain if someone was reading and didn’t understand the context. In other words, it got too complicated. But I did like the idea of having a 52-week record of my year. As I wrote in my memory-keeping post , I still want some kind of artifact that documents the year. As I wrote in that post, I used to go pretty crazy with it - big photo books documenting every single detail of my (or more likely, my kids lives). That also used to take a lot of time (which I no longer want to spend). What I’d love instead is something that captures the main points of each year, it’s 52 weeks. Something I can later drop into ChatGPT or another AI and query. For example: give me all our trips this year, big or small. Or list the events. Then I can pull that into a family photo book with just a few selected photos. So I am continuing weekly notes, just in private. Writing privately means I can include names, dates, addresses, locations, whatever I want, without curating or editing so much. The concept of weekly notes is still a really good one. I admire people who share theirs publicly and make them personal. I enjoy reading them. It’s just not me. I Choose Living Over Documenting My Photo Management and Memory Keeping Workflow On the Compulsion to Record

0 views
devansh Yesterday

Bypassing egress filtering in BullFrog GitHub Action using shared IP

This is the third vulnerability I'm disclosing in BullFrog, alongside a Bypassing egress filtering in BullFrog GitHub Action and a sudo restriction bypass in BullFrog GitHub Action . Unlike those two, which exploit specific implementation gaps, this one is a fundamental design flaw, the kind that doesn't have a quick patch because it stems from how the filtering is architected. BullFrog markets itself as a domain-based egress filter. You give it a list of domains you trust, set , and everything else should be denied. The operative word there is should . When a workflow step makes a DNS query, BullFrog intercepts the DNS response and inspects the queried domain name against your allowlist. If the domain is allowed, BullFrog takes the resolved IP address from the DNS answer and adds it to a system-level firewall whitelist (nftables). From that point on, any traffic to that IP is permitted, no further domain-level inspection. BullFrog operates at the network layer (Layer 3) and transport layer (Layer 4). It can see IP addresses and ports. It cannot see HTTP Host headers, TLS SNI values, or any application-layer content. That's a Layer 7 problem, and BullFrog doesn't go there. The modern internet is not a one-to-one mapping of domains to IP addresses. It never really was, but today it's dramatic, a single IP address on a CDN like Cloudflare or CloudFront can serve hundreds of thousands of distinct domains. BullFrog's model assumes an IP corresponds to one domain (or at least one trusted context). That assumption is wrong. Consider what gets whitelisted in a typical CI workflow: Every one of these resolves to infrastructure shared with thousands of other tenants. The moment BullFrog whitelists the IP for a registry, it has also implicitly whitelisted every other domain on that same Cloudflare edge node, including an attacker's domain pointing to the same IP. Once an allowed domain is resolved and its IP is added to the nftables whitelist, an attacker can reach any other domain on that same IP by: BullFrog never sees the Host header. The firewall sees a packet destined for a permitted IP and passes it through. The server on the other end sees the injected Host header and responds with content from an entirely different, supposedly blocked domain. The flaw lives in at agent/agent.go#L285 : Two problems in one function. First, opens the IP without any application-layer binding, all traffic to that IP is permitted, not just traffic for the domain that triggered the rule. Second, the branch in the else-if means that even a DNS query for a blocked domain gets logged as "allowed" if its IP happens to already be in the whitelist. The policy has effectively already been bypassed before the HTTP connection is even made. This PoC uses a DigitalOcean droplet running Nginx with two virtual hosts on the same IP — one "good" (allowed by BullFrog policy), one "evil" (blocked). is used as a wildcard DNS service so no domain purchase is needed. SSH into your droplet and run: Both domains resolve to the same droplet IP. BullFrog will only be told to allow . The final step returns — served by the "evil" virtual host, through a connection BullFrog marked as allowed, to a domain BullFrog was explicitly told to block. The DigitalOcean + nip.io setup is a controlled stand-in for the real threat model, which is considerably worse. Consider what actually gets whitelisted in production CI workflows: An attacker doesn't need to compromise the legitimate service. They just need to host their C2 or exfiltration endpoint on the same CDN, and inject the right Host header. The guarantee evaporates entirely for any target on shared infrastructure, which in practice means most of the internet. How BullFrog's Egress Filtering Works The Layer 3/4 Problem Shared Infrastructure is Everywhere Vulnerability Vulnerable Code Proof of Concept Infrastructure Setup The Workflow Real-World Impact Disclosure Timeline You have a dependency registry → Cloudflare CDN You have a static files resource → Azure CDN Some blog storage hosted on cloud → Google infrastructure Using the allowed domain's URL (so the connection goes to the already-whitelisted IP — no new DNS lookup, no new policy check) Injecting a different header to tell the server which virtual host to serve Your dependency registry resolves to Cloudflare. An attacker with any domain on Cloudflare can receive requests from that runner once the registry IP is whitelisted. Your static file reserve resolves to Azure CDN. Every GitHub Actions workflow that pulls artifacts whitelists a slice of Azure's IP space. Discovery & Report : 28th November 2025 Vendor Contact : 28th November 2025 Vendor Response : None Public Disclosure : 28th February 2026

0 views
David Bushell Yesterday

MOOving to a self-hosted Bluesky PDS

Bluesky is a “Twitter clone” that runs on the AT Protocol . I have to be honest, I’d struggle to explain how atproto works. I think it’s similar to Nostr but like, good? When atproto devs talk about The Atmosphere they sound like blockchain bros. The marketing needs consideration. Bluesky however, is a lot of fun. Feels like early Twitter. Nobody cool uses Twitter anymore ever. It’s a cesspit of racists asking Gork to undress women. Mastodon and Bluesky are the social platforms I use. I’ve always been tempted to self-host my own Mastodon instance but the requirements are steep. I use the omg.lol server instead. Self-hosting the Bluesky PDS is much less demanding. My setup includes: This is the host machine I glued an NVMe onto the underside. All services run as Docker containers for easy security sandboxing. I say easy but it took many painful years to master Docker. I have the Pi on a VLAN firewall because I’m extra paranoid. I setup my Bluesky PDS using the official Docker container. It’s configure with environment variables and has a single data volume mounted. I backup that volume to my NAS. I’ve put Caddy in front of the PDS container. Right now it just acts as a reverse proxy. This gives me flexibility later if I want to add access logs, rate limiting, or other plugins. Booo! If you know a good European alternative please let me know! The tunnel links Caddy to the outside world via Cloudflare to avoid exposing my home IP address. Cloudflare also adds an extra level of bot protection. The guides I followed suggest adding wildcard DNS for the tunnel. Cloudflare has shuffled the dashboard for the umpteenth time and I can’t figure out how. I think sub-domains are only used for user handles, e.g. . I use a different custom domain for my handle ( ) with a manual TXT record to verify. Allowing the PDS to send emails isn’t strictly necessary. It’s useful for password resets and I think it’ll send a code if I migrate PDS again. I went through the hassle of adding my PDS domain to Proton Mail and followed their SMTP guide . This shows how the PDS enviornment variables are formatted. It took me forever to figure out where the username and password went. PDS MOOver by Bailey Townsend is the tool that does the data migration. It takes your Bluesky password and probably sees your private key, so use at your own risk! I setup a new account to test it before I YOLO’d my main. MOOve successful! I still login at but I now select “custom account provider” and enter my PDS domain. SkyTools has a tool that confirms it. Bluesky Debug can check handles are verified correctly. PDSIs.dev is a neat atproto explorer. I cross-referenced the following guides for help: Most of the Cloudflare stuff is outdated because Cloudflare rolls dice every month. Bluesky is still heavily centralised but the atproto layer allows anyone to control their own data. I like doing that on principle. I don’t like maintenance, but I’ve heard that’s minimal for a PDS. Supposedly it’s possible to migrate back to Bluesky’s PDS if I get bored. I’m tempted to build something in The Atmosphere . Any ideas? Thanks for reading! Follow me on Mastodon and Bluesky . Subscribe to my Blog and Notes or Combined feeds. Notes on Self Hosting a Bluesky PDS Alongside Other Services Self-host federated Bluesky instance (PDS) with CloudFlare Tunnel Host a PDS via a Cloudflare Tunnel Self-hosting Bluesky PDS

1 views
Brain Baking Yesterday

An Album For Every Year Of My Life

Inspired by Tom’s One Album for Every Year of Life compilation, Robert created his own list. It’s been a while since I last published a list related to music so here’s my own that should contain 40 items. This was a much more challenging exercise than I initially thought. It took me almost an entire day to compile the list and it still contains holes. In any case, scrolling through the list is another way to reveal the evolution of my musical taste . Each row includes a sample track I picked out for your listening pleasure. Every link redirects to YouTube to keep things as simple as possible. The idea is that these samples make the list a bit more interesting for people who are looking into expanding their musical tastes. Album art: the eighties. Very easy to compile. Genres: metal, pop/rock, new wave/synth. I love eighties music as is apparent by having the GTA Vice City radio stations on repeat for years and years. I kind of cheated by including two compilation albums in this list of which Decade is the first: all the good stuff is from before 1985. There’s so much great new wave/synth pop music out there, but I have yet to discover the full length albums as I usually aim for the more popular individual tracks. When I’m in the mood, I appreciate the odd metal/hard rock track, but as will become clear in the next section, it’s not my main genre. Album art: the nineties. Very easy to compile. Genres: rap overload! My music nineties are heavily dictated by hip-hop super-groups of which Wu-Tang’s Enter The Wu-Tang is the most influential. Since then, I’ve been a devout Wu follower as is apparent from the spin-offs ( Gravediggaz ) and solo albums ( Liquid Swords ) on this list. Beyond a good doze of underground rap, there’s also the king of the G-Funk. I first had the new king listed on 1999 ( Dr Dre: Chronic 2001 ) but Dan The Automator’s weird stuff takes more priority. The few non-rap albums are either compilations ( Middle of the Road ) that my mother brainwashed me with or late pop rock goodies (I love Genesis but hate their slow songs). Album Art: the noughties. Moderately difficult to compile. Genres: alternative/underground rap, electronic. I faced difficulties filling the latter half of the noughties as my musical brain was stuck in either the golden age of rap (the nineties) or the golden age of synth music (the eighties). Still, this decade includes some of the best albums ever made ( Madvilliany ) and great super-group deliverables that I’ll listen to any day ( Jurassic 5 & Hieroglyphics ). Much later, I discovered I also love chiptune music and electronic (rock). The inclusions here are recent aquisitions: in the noughties, my mind was still very much set on rap. Album art: the 2010s. Difficult to compile. Genres: hip-hop, electronic, funk. Mega Ran is probably my biggest discovery from this time: an MC rapping about video games and remixing classic video game soundtracks? Here’s my wallet, where do I sign? More chiptune electronic starts finding its way into my playlist feed, with Cory Wong and his Vulfpeck as the latest funky additions. Album art: the 2020s. Impossible to compile. Genres: Hip-hop, funk, electronic. Most albums I buy nowadays are released in the previous decade(s); I’m a “slow discoverer” when it comes to contemporary music: hence the absence of entries in the years 2024, 2025, 2026. If you have any suggestion based on my taste laid out here please let me know. I’m happy to report that hardcore hip-hop is not dead yet. Czarface proves this—yet another Wu spin-off by original Wu member Inspectah Deck and the duo 7L & Esoteric . They consistently put out great comic book inspired stuff. I just learned about Stress Eater , a spin-off involving Kool Keith . Maybe that album should be on 2024 in a few months. Related topics: / music / By Wouter Groeneveld on 2 March 2026.  Reply via email .

0 views
iDiallo Yesterday

Why we feel an aversion towards LLM articles

Last year, I pushed myself to write and publish every other day for the whole year. I had accumulated a large number of subjects over the years, and I was ready to start blogging again. After writing a dozen or so articles, I couldn't keep up. What was I thinking? 180 articles in a year is too much. I barely wrote 4 articles in 2024. But there was this new emerging technology that people wouldn't stop talking about. What if I used it to help me achieve my goal? Have you ever heard of Mo Samuels? You probably haven't. But you must have heard of Seth Godin , right? Seth Godin is the author of several bestsellers. He is an icon in the world of marketing, and at one point he nudged me just enough to quit an old job. This is someone I deeply respected, and I bought his book All Marketers are Liars with great anticipation. I was several chapters in when he dropped this statement: I didn't write this book. What does he mean by that? His name is on the cover. These are the familiar words I often heard in his seminars. What is he trying to say? What I mean is that Seth Godin didn't write this book. It was written by a freelancer for hire named Mo Samuels. Godin hired me to write it based on a skimpy three-page outline. What? Mo Samuels? Who is Mo Samuels? If that name were on the cover, I wouldn't have bought the book in the first place. Does that bum you out? Does it change the way you feel about the ideas in this book? Does the fact that Seth paid me $10,000 and kept the rest of the advance money make the book less valuable? Well, yeah. It doesn't change the ideas in the book. But it is deceptive. I bought it specifically to read his words. Not someone else's. Why should it matter who wrote a book? The words don't change, after all. Yet I'm betting that you care a lot that someone named Mo wrote this book instead of the guy on the dust jacket. In fact, you're probably pretty angry. Well, if you've made it this far, you realize that there is no Mo Samuels, and in fact, I was pulling your leg. I (Seth Godin) wrote every word of this book. Imagine he hadn't added that last line. I never return a book after purchase, but this would have been a first. We don't just buy random books, a name carries value. I bought this book specifically because I wanted insight from this author. Anything less would have been a betrayal. Well, that's how people feel when they read an LLM-generated article. I wouldn't have noticed if I hadn't used LLMs to write articles on this very blog. The first time, I wrote a draft that had all the elements I wanted to present. The problem was the structure didn't entirely make sense. The story arc didn't really pay off, and the pacing was off. DeepSeek was just making the rounds, releasing open weights and open source code. I decided to use it to help me structure the article. The result was impressive. Not only had it fixed the pacing, it restructured the article in a way that made much more sense. Where I had dense blocks of information, DeepSeek turned them into convenient bullet points that were much easier to read. I was satisfied with the result and immediately published it. What I failed to notice, or maybe was too mesmerized to notice, was that the sentence structure had also been rewritten. I didn't use LLMs every time I wrote, but throughout the year I had at least a dozen AI-enhanced articles. When publishing, they sounded just fine. The problem started when I wanted to reference one of those articles in a new post. Reading through the AI-enhanced post felt strange. A paragraph I vaguely remembered and wanted to quote didn't sound like what I remembered. The articles were bloated with words I would never use. They had quips that seemed clever at the time but didn't sound like me at all. I ended up rewriting sections of those posts before quoting them. The second problem appeared whenever I landed on someone else's blog. I noticed the same patterns. The same voice. The same quips. "It's not just X, but Y." "Here's the part I find disturbing." "The irony is not lost on me." "It is a stark reminder." These and many more writing tropes were uniformly distributed across my LLM-assisted articles and countless others across the web. It felt like Mo Samuels was a guest writer on all of our blogs. And here's the kicker: (another famous thrope) I'm not singling out DeepSeek here. ChatGPT, Claude, Gemini, they all seem to have taken the same "Writing with Mo Samuels" Master class. It feels like this voice, no matter what personality you try to prompt it with, is the average of all the English language on the web. I wouldn't say readers of this blog are here for my distinct voice or writing style. I'm not famous or anything. But I know they can spot Mo from a mile away. My goal is not to trick readers. I want the stories and work experiences I share here to come from me, and I want to give readers that same assurance. So here is what I did. Since my goals are more modest this year, I've rewritten several of those lazy articles. I spend more time writing, and I try to hold onto this idea that's gaining traction among bloggers: "If you didn't bother writing, why should anyone bother reading?" I want to share my thoughts, even if no one reads them. When I come back to rediscover my own writing, I want to recognize my own voice in it. But if you do read this blog, if it sucks, if you disagree, if you have an opinion to share, you should know that I wrote it. Not Mo Samuels.

0 views
ava's blog Yesterday

AI clones and data protection

A few days ago, news spread through the web about a Meta project for letting an AI run the social media account of a deceased person, as it could emulate the person's activity like posting content and responding to messages. The goal was to maintain engagement on the platform and reduce the grief when a person passes away. If you believe a screenshot going around, a poster on 4chan revealed this years prior, saying it has the internal name " Project Lazarus ", referencing the Lazarus of Bethany . While Meta spokespeople said they had no plans to pursue this (yet?), there are other services like ELIXIR AI , who want to push digital immortality via an " eternal doppelganger from a customer's lifetime data ". In general, we are already dealing with a deluge of deepfakes online. Not only are people using AI to remove the clothes on the images of people, but they are also creating new images, video and audio material with a person's physical and vocal likeness, trained on even just a handful of photos, up to terabytes of video material if it's a popular and active YouTuber. This also happens in the education and entertainment industry. Notable figures have digital copies in museums and other places to be interacted with, and deceased actors get "revived" to show up or to lend their voice to a character. Researchers talk about this as " spectral labour " in a " postmortal society ", meaning the " exploitation of digital remains for aesthetically pleasing, politically charged, and communicative representations ". The companies that provide these resurrection services are referred to as "* transcendence industry ". The tech and availability is changing fast, and as with any developing field, it can be hard to apply existing legal frameworks that didn't have this use case in mind specifically. While I have to leave the issues around general ethics and monetization to another day, I'd like to focus further on ( European ) data protection and privacy laws! First up, good to know: Are your body and voice capable of being personal data? Yes! They make you identifiable. You can also see this in Article 9 GDPR , which prohibits processing data related to racial or ethnic origin, and the processing of genetic data, biometric data for the purpose of uniquely identifying a natural person and data concerning health, unless it falls into very specific allowed purposes. Your body carries this type of information. Additionally, the European Data Protection Board has also given out guidelines that suggest that voice data is considered inherently biometric . That means making a model of you via a series of photos from different angles, motion capture, voice recordings etc. is processing personal data, some of it sensitive data under Article 9 GDPR . This is then further processed during AI training and finetuning to reproduce a person's physical or vocal likeness reliably. Recital 51 of the GDPR mentions: " The processing of photographs should not systematically be considered to be processing of special categories of personal data as they are covered by the definition of biometric data only when processed through a specific technical means allowing the unique identification or authentication of a natural person. " So, simply taking or editing some pictures is not considered processing of special (sensitive) personal data, as this would reach too far; it needs specific technical means that take measurements to turn it into biometric data, like when you set up to unlock your phone for FaceID, or if you get an eye scan or fingerprint scan to be able to unlock a door with your eye or finger. There are actually quite a few interesting discussions on whether taking a picture of someone wearing glasses is processing data about their health - but I digress. AI models trained on reproducing your likeness reliably have turned you into a dataset, a bunch of measurements, a model, which generally counts as biometric data processing. Once data processing falls under Article 9 GDPR , legal bases of Article 6 GDPR - like legitimate interest, fulfillment of a contract, compliance, etc. - fall away, as only the specific allowances of Article 9(2) GDPR make an exception from the general prohibition. In the case of the entertainment and education industry, that will likely reduce it to the explicit consent named in: " a) the data subject has given explicit consent to the processing of those personal data for one or more specified purposes, except where Union or Member State law provide that the prohibition referred to in paragraph 1 may not be lifted by the data subject " This impossible for people who have already passed away, but you can usually ask their estate/remaining family members for consent in their stead though. Consent, under GDPR, always needs to be given freely. Article 7 GDPR says, among other things, " When assessing whether consent is freely given, utmost account shall be taken of whether, inter alia, the performance of a contract, including the provision of a service, is conditional on consent to the processing of personal data that is not necessary for the performance of that contract. " It's also referred to as the Coupling prohibition . That may be difficult to avoid in the entertainment industry: What if getting the role is tied to agreeing with AI cloning, even if not explicitly, then implicitly? What if refusing, at some point, gets you blacklisted? What if agreeing has an effect on your success and income at an agency? Many actors now have to deal with this as studios try to reduce the time spent on set for actors to reduce costs via AI clones, and also want a backup AI clone option in case the actor dies during production. What's also problematic: How do you you freely and productively consent to something you don't understand? Of course, you don't need to be an expert in everything, but usually, stuff is pretty straightforward in terms of taking pictures, video or audio recordings. Explaining how AI models work has been very difficult, even for people deeply involved, but now we are likely dealing with studios who are completely uninvolved with the company that actually handles the AI cloning. And also, how do you properly inform someone contractually about how their data will be used and processed if the field and possibilities develop so fast? It's difficult to anticipate potential future use cases you'd want or not want. And if the data gets sent to somewhere outside of the EEA, you have a so-called ' third country transfer ' to worry about, which needs special considerations and protections. Now, we have established that your body and voice are personal data, and that processing them in this way falls under the GDPR. What about your clone data within the training set, or the output itself? This is a bit controversial at the moment! It makes sense that this would also be regarded as personal data, as it is still identifiably you when it gets used with zero alterations. Where it gets problematic are use cases where you lend your likeness to something, especially your voice. For example: Use for an ad that is not supposed to literally embody you, but instead just offer a neutral voice-over; or you're the new voice for Siri; or you might synchronize a cartoon character. Obviously, your friends and family could reliably recognize your voice, so it could count. But there are data protection authorities in Germany who vouch for a more usage-oriented interpretation, meaning: If your clone is used to identify you and represent you in some content, it is biometric identification, but if your voice is just used as one voice for a job, it's just imitation or synthesis. I don't agree with that, as the data itself and the identification methods are still the same and current synthesis usage can still be used for biometric identification later, but that's the discussion right now. Okay, so this type of data generally falls under the GDPR. That means I have the same rights as usual - right to deletion, too. But how I said before in my post about AI and the GDPR , it can be hard or impossible to delete data from a training set. Deleting the entire model or having to retrain it would incur massive costs and losses; it would make more sense instead to have more individual models that can be more easily separated and deleted, if possible. But since that is not in control of the person holding the rights, it might be hard to enforce them. It's equally difficult for the output of these models: That falls under the GDPR as well and would be affected by the deletion or restriction requests, but that's also where lots of contracts, laws and rights collide. It needs to be assessed in each case individually. There was an interesting case in Germany a while ago: A YouTuber using an AI generated voice from a famous voice actor in his videos, and the actor objecting to it. The YouTuber had around 190,000 subscribers and an associated online shop. He published two political satire videos on YouTube that used an AI-generated voice that closely imitated the actor’s voice, but didn't label that it was AI. Viewers in the comments identified the voice as the actor's as well. The videos ended with references to the online shop, which sold merchandise linked to the channel’s political opinions. The actor objected to the use of his voice towards the YouTuber and requested he stops, and wanted reimbursement of legal costs. The YouTuber agreed to cease, but refused to pay damages, arguing that the voice was synthetic, lawfully acquired from an AI voice provider, and used for satire rather than advertising. Meanwhile, the actor claimed that the AI-generated voice constituted use of his personal voice, that the processing occurred without consent, and that it created the impression that he endorsed the videos and products. He now also sought compensation equivalent to his usual licensing fees. The court sided with the actor and saw that the YouTuber interfered with the actor’s right to his own voice, as despite being AI, the voice closely imitated a distinctive personal characteristic. The court considered that a significant part of the audience would associate the voice with the data subject, which was sufficient to establish personal attribution. As expected and further explained above, the court rejected the reasoning of "legitimate interest" in Article 6(1)(f) GDPR , and saw that the voice primarily served the YouTuber's commercial interests. No exemption applied under Article 85 GDPR as the processing was neither journalistic nor genuinely artistic in a way that would justify overriding the data subject’s rights, particularly given the commercial context and the lack of transparency about the AI-generated nature of the voice. As a consequence, the court ordered the YouTuber to pay €4,000 as a fictitious license fee for the unauthorized use of the voice and €1,155.80 for reimbursable legal costs, plus interest. I think it's important to talk about this as it doesn't only affect actors and voice actors, or historical people's likeness used in the classroom or at concerts, but also has the potential to affect you. Your employer could ask to make an AI clone of you, for example. At the data protection law conference I attended in Munich, the AI Officer of a big insurance firm said they are holding the data protection trainings required for their employees via AI generated videos and AI generated avatars of him and his colleague. That means employees that need to do the training get in a digital environment with this avatar of him that responds, smiles, blinks and leads them through the material, some of which is AI generated as well. Circling back again to this research paper , we are at a point in time where, depending on your job, your body and voice can work independently of you, and people can monetize you after your death not by further selling what you produced in your lifetime, but producing new things indefinitely that you had no hand in while you were life, or selling access to "you". Eerie, huh? So it's important to know your rights and what's going on in the space :) Reply via email Published 02 Mar, 2026

0 views
Stratechery Yesterday

Anthropic and Alignment

Just because you do not take an interest in politics doesn’t mean politics won’t take an interest in you. ― Pericles This is not an Article about the campaign being waged by the U.S. against Iran, but it’s a useful — and timely — analogy. There is a never-ending debate that can be had about the concept of International Law and who might be violating it. Some will argue that the U.S. is in violation for the attacks; others will note that Iran has been serially violating International Law with both its overt actions and its support of terror networks for my entire life. What is important to note is that the entire debate is ultimately pointless: the very concept of “international law” is fake, not because pertinent statutes and agreements don’t exist, but because their effectiveness is ultimately rooted in their enforceability. That, by extension, means there must be an entity to enact such enforcement, with the capability to match, and such an entity does not exist. Yes, there is the United Nations, but said body only operates by the agreement of its members, and their willingness to subjugate themselves to not only its edicts, but to also put forward the capabilities to enforce its mandates. In other words, the only agents that matter are nation states themselves, and the relative power of those nation states is not a function of lawyers and judges but rather their ability to project force and coerce others. To put it another way, if, after this weekend, you want to hold onto the concept of International Law, then realize the debate has been resolved: Iran was in violation, because their military just had their clock cleaned by the U.S., which means the U.S. decides who is right and who is wrong. While most of the U.S. and certainly the rest of the world were preoccupied with the happenings in Iran, another fervent debate has been ongoing in tech. Once again one of the parties is the United States itself, but the other entity in question is a private company, Anthropic. From the Wall Street Journal : The federal government will stop working with Anthropic and designate the artificial intelligence company a supply-chain risk, a dramatic escalation of the government’s clash with the company over how its technology can be used by the Pentagon. While Anthropic’s relationship with the administration hit a new low, rival OpenAI said late Friday that it reached an agreement with the Defense Department to have its models used in classified settings, until recently a status only held by Anthropic. Friday’s quick-fire developments between the Pentagon and two Silicon Valley darlings are poised to shape the future of how the federal government and, particularly the Pentagon, uses cutting-edge AI tools. Anthropic staked out its position earlier in the week in a Statement from Dario Amadei on [its] discussions with the Department of War : In a narrow set of cases, we believe AI can undermine, rather than defend, democratic values. Some uses are also simply outside the bounds of what today’s technology can safely and reliably do. Two such use cases have never been included in our contracts with the Department of War, and we believe they should not be included now: To our knowledge, these two exceptions have not been a barrier to accelerating the adoption and use of our models within our armed forces to date. The Department of War has stated they will only contract with AI companies who accede to “any lawful use” and remove safeguards in the cases mentioned above. They have threatened to remove us from their systems if we maintain these safeguards; they have also threatened to designate us a “supply chain risk” — a label reserved for US adversaries, never before applied to an American company — and to invoke the Defense Production Act to force the safeguards’ removal. These latter two threats are inherently contradictory: one labels us a security risk; the other labels Claude as essential to national security. Regardless, these threats do not change our position: we cannot in good conscience accede to their request. I actually didn’t realize before this episode that the National Security Agency (NSA) is a part of the Department of War; that certainly provides useful context around the surveillance point. And, as we saw a decade ago with the Snowden revelations, the NSA can be both aggressive and creative in its interpretations of what is legal in terms of surveillance. One might have hoped that telecom companies in particular might have taken a stand like Anthropic did. At the same time, what is the standard by which it should be decided what is allowed and not allowed if not laws, which are passed by an elected Congress? Anthropic’s position is that Amodei — who I am using as a stand-in for Anthropic’s management and its board — ought to decide what its models are used for, despite the fact that Amodei is not elected and not accountable to the public. And, on the second point, who decides when and in what way American military capabilities are used? That is the responsibility of the Department of War, which ultimately answers to the President, who also is elected. Once again, however, Anthropic’s position is that an unaccountable Amodei can unilaterally restrict what its models are used for. It’s worth noting that there are reports that Anthropic’s concerns may be broader than just fully autonomous weapons; from Semafor : Anthropic is one of the few “frontier” large language models available for classified use by the US government because it is available through Amazon’s Top Secret Cloud and through Palantir’s Artificial Intelligence Platform, which is how its Claude chatbot ended up appearing on the screens of officials who were monitoring the seizure of then-Venezuelan President Nicolás Maduro… Soon after the Maduro raid, during a regular check-in that Palantir holds with Anthropic, an Anthropic official discussed the operation with a Palantir senior executive, who gathered from the exchange that the AI startup disapproved of its technology being used for that purpose. The Palantir executive was alarmed by the implication of Anthropic’s inquiry that the company might resist the use of its technology in a US military operation, and reported the conversation back to the Pentagon, a senior Defense Department official said. Anthropic denied it objected to whatever involvement Claude may have had in the Maduro raid, but the Semafor story resonates given the trend in some tech circles to resist any involvement in military operations. And, to that end, one could argue that this stand-off is ending as it should: Anthropic and its models will be removed from the Department of War tech stack, and an alternative will take their place. Amodei has been outspoken about other aspects of AI and national security; from Bloomberg in January : Anthropic Chief Executive Officer Dario Amodei said selling advanced artificial intelligence chips to China is a blunder with “incredible national security implications” as the US moves to allow Nvidia Corp. to sell its H200 processors to Beijing. “It would be a big mistake to ship these chips,” Amodei said in an interview with Bloomberg Editor-in-Chief John Micklethwait at the World Economic Forum in Davos, Switzerland. “I think this is crazy. It’s a bit like selling nuclear weapons to North Korea.” This rather raises the stakes of a messy procurement decision: consider the implications if we take Amodei’s analogy literally. Start with Iran: beyond the fact that Iran has been responsible for the deaths of thousands of Americans throughout the Middle East and beyond, one of the arguments for the U.S. intervention is that Iran continues to pursue nuclear weapons capabilities. It’s North Korea that shows why: North Korea doesn’t need to buy nuclear weapons, because they already have them, and it certainly makes any sort of potential military action against them considerably more complicated. Nuclear weapons make you an effective lawyer in the (nonexistent 1 ) court of international law! In short, nuclear weapons meaningfully tilt the balance of power; to the extent that AI is of equivalent importance is the extent to which the United States has far more interest in not only what Anthropic lets it do with its models, but also what Anthropic is allowed to do period. This, I think, gives important context to the designation of Anthropic as a supply chain risk. Secretary of War Pete Hegseth said on X : In conjunction with the President’s directive for the Federal Government to cease all use of Anthropic’s technology, I am directing the Department of War to designate Anthropic a Supply-Chain Risk to National Security. Effective immediately, no contractor, supplier, or partner that does business with the United States military may conduct any commercial activity with Anthropic. This would decimate Anthropic: at a bare minimum the company relies on cloud hosting from AWS, Microsoft, and Google, all of which have contracts with the Department of War; I imagine the same applies to Nvidia. Fortunately for the company, Hegseth’s declaration does seem out of step with the law , which limits Hegseth’s authority to work covered by U.S. government contracts; in other words, AWS could still serve Anthropic models, as long as it doesn’t use Anthropic models for any of its services offered to the U.S. government. Regardless, this is an extreme measure that has been met with near universal dismay, even amongst people who are sympathetic to the idea that a private company should not have veto power over the U.S. military. Why would the U.S. government want to kneecap one of its AI champions? In fact, Amodei already answered the question: if nuclear weapons were developed by a private company, and that private company sought to dictate terms to the U.S. military, the U.S. would absolutely be incentivized to destroy that company. The reason goes back to the question of international law, North Korea, and the rest: Anthropic talks a lot about alignment; this insistence on controlling the U.S. military, however, is fundamentally misaligned with reality. Current AI models are obviously not yet so powerful that they rival the U.S. military; if that is the trajectory, however — and no one has been more vocal in arguing for that trajectory than Amodei — then it seems to me the choice facing the U.S. is actually quite binary: Note that I’m not making the (very good) argument put forward by Anduril founder Palmer Luckey about the importance of democratic oversight; Luckey wrote on X : This gets to the core of the issue more than any debate about specific terms. Do you believe in democracy? Should our military be regulated by our elected leaders, or corporate executives?… The fact that this is a debate over AI does not change the underlying calculus. The same problems apply to definitions and use of ethically fraught but important capabilities like surveillance systems or autonomous weapons. It is easy to say “But they will have cutouts to operate with autonomous systems for defensive use!”, but you immediately get into the same issues and more — what is autonomous? What is defensive? What about defending an asset during an offensive action, or parking a carrier group off the coast of a nation that considers us to be offensive? At the end of the day, you have to believe that the American experiment is still ongoing, that people have the right to elect and unelect the authorities making these decisions, that our imperfect constitutional republic is still good enough to run a country without outsourcing the real levers of power to billionaires and corpos and their shadow advisors. I still believe. And that is why “bro just agree the AI won’t be involved in autonomous weapons or mass surveillance why can’t you agree it is so simple please bro” is an untenable position that the United States cannot possibly accept. Again, I think this is a good argument; the one I am putting forward, however, is much more basic and brutal, and doesn’t have anything to do with belief or not in the American experiment (although I’m with Luckey in that regard): it simply isn’t tolerable for the U.S. to allow for the development of an independent power structure — which is exactly what AI has the potential to undergird — that is expressly seeking to assert independence from U.S. control. I don’t, for the record, want Anthropic to be destroyed, and I want them to be a U.S. AI champion. I also, for the record, don’t trust Amodei’s judgment in terms of either national security or AI security. In terms of national security, I already commented on Amodei’s Davos comments on X : Last year I laid out in AI Promise and Chip Precariousness why I believed a systemic view of the U.S.-China rivalry entailed some painful tradeoffs when it came to chips and China: The important takeaway that is relevant to this Article is that Taiwan is the flashpoint in both scenarios. A pivot to Asia is about gearing up to defend Taiwan from a potential Chinese invasion or embargo; a retrenchment to the Americas is about potentially granting — or acknowledging — China as the hegemon of Asia, which would inevitably lead to Taiwan’s envelopment by China. This is, needless to say, a discussion where I tread gingerly, not least because I have lived in Taipei off and on for over two decades. And, of course, there is the moral component entailed in Taiwan being a vibrant democracy with a population that has no interest in reunification with China. To that end, the status quo has been simultaneously absurd and yet surprisingly sustainable: Taiwan is an independent country in nearly every respect, with its own border, military, currency, passports, and — pertinent to tech — economy, increasingly dominated by TSMC; at the same time, Taiwan has not declared independence, and the official position of the United States is to acknowledge that China believes Taiwan is theirs, without endorsing either that position or Taiwanese independence. Chinese and Taiwanese do, in my experience, handle this sort of ambiguity much more easily than do Americans; still, gray zones only go so far. What has been just as important are realist factors like military strength (once in favor of Taiwan, now decidedly in favor of China), economic ties (extremely deep between Taiwan and China, and China and the U.S.), and war-waging credibility. Here the Ukraine conflict and the resultant China-Russia relationship looms large, thanks to the sharing of military technology and overland supply chains for oil and food that have resulted, even as the U.S. has depleted itself. That, by extension, gets at another changing factor: the hollowing out of American manufacturing under Pax Americana has been directly correlated with China’s dominance of the business of making things, the most essential war-fighting capability. Still, there is — or rather was — a critical factor that might give China pause: the importance of TSMC. Chips undergird every aspect of the modern economy; the rise of AI, and the promise of the massive gains that might result, only make this need even more pressing. And, as long as China needs TSMC chips, they have a powerful incentive to leave Taiwan alone. The key thing to consider is the opposite scenario: cutting China off from advanced chips doesn’t just reduce the likelihood that Chinese companies are dependent on a U.S.-based ecosystem, it also reduces the cost of destroying TSMC. More than that, if AI becomes as capable as Amodei says it will — the equivalent, or more, of nuclear weapons — then it actually becomes game theory optimal for China to do exactly that: if China can’t have AI, then it is, at least under current circumstances, relatively easy to make sure that nobody does. Amodei is, as the quote above notes, cognizant of China as a threat generally; it concerns me that he consistently fails to acknowledge that the implication of his recommended course of action in terms of chip controls is to risk destroying AI for everybody. Then again, Amodei isn’t really a fan of AI for everybody: he and Anthropic have been vocal opponents of open source models, and were major drivers of what I considered a very misguided Biden executive order about AI . Like the Taiwan situation, I think these positions evince a failure to think systematically: There is certainly room for disagreement on these points; what concerns me about Amodei and Anthropic in particular is the consistent pattern of being singularly focused on being the one winner with all of the power, with limited consideration of how everyone else may react to that situation. Or, to be more blunt, the reality that other people exist and they have guns and missiles and yes, nuclear weapons. Might still makes right, and I personally would rather not hand over the future of humanity to a person and a company that seems to consistently forget that fact. I do think this post on X from Ramez Naam is the most optimistic way to frame the debate this weekend: I do have tremendous discomfort about AI’s surveillance capabilities in particular; there are a lot of safeguards we thought we had that were actually mostly due to the friction entailed in overcoming them. AI, even more than computers and the Internet, is a friction solvent, and I completely understand why Anthropic’s pushback on this specific point resonates broadly. The way to address this new reality, however, is with new laws and through strengthening accountable oversight; cheering or even demanding that an unelected executive decide how and where such powerful capabilities can be used is the road an even more despotic future. Our adversaries, meanwhile, will certainly be developing autonomous fighting capabilities (and yes, I admit my chip prescriptions make this more likely much sooner — tradeoffs are hard!); the U.S. will need to move in this direction if we are to remain the ultimate source of international law. And, by the U.S., I mean a democratically elected President and Congress, not a San Francisco executive. I don’t want that, and, more pertinently, the ones with guns aren’t going to tolerate it. Anthropic needs to align itself with that reality. Yes, The Hague exists; its subject to all of the same limitations as the United Nations  ↩ Mass domestic surveillance. We support the use of AI for lawful foreign intelligence and counterintelligence missions. But using these systems for mass domestic surveillance is incompatible with democratic values. AI-driven mass surveillance presents serious, novel risks to our fundamental liberties. To the extent that such surveillance is currently legal, this is only because the law has not yet caught up with the rapidly growing capabilities of AI. For example, under current law, the government can purchase detailed records of Americans’ movements, web browsing, and associations from public sources without obtaining a warrant, a practice the Intelligence Community has acknowledged raises privacy concerns and that has generated bipartisan opposition in Congress. Powerful AI makes it possible to assemble this scattered, individually innocuous data into a comprehensive picture of any person’s life—automatically and at massive scale. Fully autonomous weapons. Partially autonomous weapons, like those used today in Ukraine, are vital to the defense of democracy. Even fully autonomous weapons (those that take humans out of the loop entirely and automate selecting and engaging targets) may prove critical for our national defense. But today, frontier AI systems are simply not reliable enough to power fully autonomous weapons. We will not knowingly provide a product that puts America’s warfighters and civilians at risk. We have offered to work directly with the Department of War on R&D to improve the reliability of these systems, but they have not accepted this offer. In addition, without proper oversight, fully autonomous weapons cannot be relied upon to exercise the critical judgment that our highly trained, professional troops exhibit every day. They need to be deployed with proper guardrails, which don’t exist today. International law is ultimately a function of power; might makes right. There are some categories of capabilities — like nuclear weapons — that are sufficiently powerful to fundamentally affect the U.S.’s freedom of action; we can bomb Iran, but we can’t North Korea. To the extent that AI is on the level of nuclear weapons — or beyond — is the extent that Amodei and Anthropic are building a power base that potentially rivals the U.S. military. Option 1 is that Anthropic accepts a subservient position relative to the U.S. government, and does not seek to retain ultimate decision-making power about how its models are used, instead leaving that to Congress and the President. Option 2 is that the U.S. government either destroys Anthropic or removes Amodei. First, were there only closed AI systems, then unimaginable power would be vested in the owners of those systems; it seems that Amodei thinks that power should be wielded by him (at a minimum, I would prefer that be wielded by the U.S. government). Second, the idea that AI safety can only be guaranteed by a limited number of responsible stewards ignores the massive incentives that exist to build other models. This was clear years ago when only a few companies were working on AI models, and has been proven out by what has happened in reality so far. Third, in a world of AI proliferation, the best defense against AI will be AI; this means that more AI is actually safer than limited AI, which means open source is ultimately safer. Yes, The Hague exists; its subject to all of the same limitations as the United Nations  ↩

0 views
ava's blog Yesterday

small thoughts part 8

In ‘ small thoughts ’ posts, I’m posting a collection of short thoughts and opinions that don’t warrant their own post. :) It's been a while! I’m looking back and am so grateful for everything I got myself through. The times I was alone, sick, in pain but still went to appointments, walked the dog, got groceries and picked up meds. The way I still always kept my home clean or resolved a pile of dishes after a few days. The way I would plan self care for myself; baths, making myself good meals, booking massages, scheduling walks in the forests, making playlists for these walks. Making time to stretch, to meditate, to do a little ritual for myself, or the evenings I spent hours helping strangers online while sipping on my tea, feeling cozy, safe, content, in my own world. I remember all the times I set out to watch something either on my TV or PC and prepared a thermos so I’d have lots of tea and not have to get up, and arranged cookies and nuts and some bread or fruits on a board for me. All the creams on my face and body, my hair. I’m so glad I did that. Now my wife does a lot of these for me. I think one day we will look back on this and realized we lived the dream. Just buying whatever we want at the grocery store, buying a lot for our shared niche hobbies, my wife being home all the time due to being unemployed, me being home most of the week, home office after all work’s done spent taking baths and gaming and grocery shopping and painting and watching things together, cleaning together, getting nails done… I used to think peoplewatching is for judging them, because that’s what my mum always did. But you can just watch them neutrally, or even compliment them in your head. People get less scary to me after spending time peoplewatching. It’s like in everyday life, they’re like cars I dodge on my way to something, and bad experiences stick out for longer. But when I am just a body observing somewhere in a corner, everyone is so human to me. So many people look interesting to talk to. I see little details on them that tell a story. Maybe I should make it a habit to sit in this café weekly, observing, sitting there with my notebook, and trying to talk to people who look inviting and like they wouldn’t mind. It would be a good practice for my hesitancy to talk to others, too. Too bad I usually have a job to do around this time. I guess I could try working from here, but it’s less nice. I always recover from a sort of work-induced misanthropy during time off, and when I have to work with people again or commute, it all comes back. Do I idealize people once they’re strangers from a distance, and just notice how rotten people are once I get close and am affected by their actions? I hate how my job burns me out on people and it’s not even customer-facing; it’s other employees causing me to feel that way. I wonder what the truth is; if my job is a bad influence on my view on people, or if it’s easy to love them from afar. Maybe both. The truth might be in the middle. I could work a job that makes me love people more, and I can acknowledge that it’s easy to think a stranger seems nice when you don’t actually know them. I regret leaving my notebook at home. I’d prefer to write this in there and not type it in my phone. Thinking about how it has never been easier to socialize, technically . Yes, third spaces disappear, yes less being outside; but all the messaging, video calling, social media, feeds, aggregators etc. lets you meet hundreds of people so quickly. Your selection to choose from is so much bigger than just locally. There’s more opportunities for travel for the average person compared to just 100 years ago, too. Lots like that, and still we complain about disconnection. I see it and I think, maybe it’s not necessarily that we live in disconnected times in general; it’s that you replaced connection with consumption of podcasts, and you frequently leave or never even join messaging servers and group chats, and you delete you accounts and purge your friend lists every couple months. You put off responding to messages and emails, and you lurk in most spaces you have accounts in, and you lock your profile and hide yourself from feeds. So? How are you supposed to capitalize on the social aspect of it all? It would be impossible to create a tool to help you. Change has to come from you. You have to open yourself up to receive love. Reply via email Published 02 Mar, 2026

0 views
Lea Verou Yesterday

External import maps, today!

A few weeks ago, I posted Web dependencies are broken. Can we fix them? . Today’s post is a little less gloomy: Turns out that the major limitation that would allow centralized set-it-and-forget-it import map management can be lifted today, with excellent browser support! The core idea is that you can use DOM methods to inject an import map dynamically , by literally creating an element in a classic (blocking) script and appending it after the injector script. 💡 This is a gamechanger. It makes external import maps nice-to-have sugar instead of the only way to have centralized import map management decoupled from HTML generation. All we need to do is build a little injector script, no need for tightly coupled workflows that take over everything. Once you have that, it takes a single line of HTML to include it anywhere. If you’re already using a templating system, great! You could add to your template for every page. But you don’t need a templating system: even if you’re rawdogging HTML (e.g. for a simple SPA), it’s no big deal to just include a in there manually. This is not even new: when the injector is a classic (non-module) script placed before any modules are fetched, it works in every import map implementation , all the way back to Chrome 89, Safari 16.4+, and Firefox 108+ ! Turns out, JSPM made the same discovery: JSPM v4 uses the same technique . It is unclear why it took all of us so long to discover it but I’m glad we got there. First, while there is some progress around making import maps more resilient, your best bet for maximum compatibility is for the injector script to be a good ol’ blocking that comes before everything else. This means no , no , no — you want to get it in before any modules start loading or many browsers will ignore it. Then, you literally use DOM methods to create a and append it after the script that is injecting the import map (which you can get via ). This is a minimal example: Remember, this literally injects inline import maps in your page. This means that any relative URLs will be interpreted relative to the current page ! If you’re building an SPA or your URLs are all absolute or root-relative, that’s no biggie. But if these are relative URLs, they will not work as expected across pages. You need to compute the absolute URL for each mapped URL and use that instead. This sounds complicated, but it only adds about 5 more lines of code: Note that is in module scripts, since the same module can be loaded from different places and different scripts. Once it becomes possible to inject import maps from a module script, you could use to get the URL of the current module. Until then, you can use a bit of error handling to catch mistakes: This is the minimum, since the script literally breaks if is . You could get more elaborate and warn about / attributes, or if scripts are present before the current script. These are left as an exercise for the reader. While this alleviates the immediate need for external import maps , the DX and footguns make it a bit gnarly, so having first-class external import map support would still be a welcome improvement. But even if we could do today, the unfortunate coupling with HTML is still at the receiving end of all this, and creates certain limitations, such as specifiers not working in worker scripts . My position remains that HTML being the only way to include import maps is a hack . I’m not saying this pejoratively. Hacks are often okay — even necessary! — in the short term. This particular hack allowed us to get import maps out the door and shipped quickly, without getting bogged down into architecture astronaut style discussions that can be non-terminating. But it also created architectural debt . These types of issues can always be patched ad hoc, but that increases complexity, both for implementers and web developers. Ultimately, we need deeper integration of specifiers and import maps across the platform . (with or without an attribute) should become a shortcut , not the only way mappings can be specified. In my earlier post, I outlined a few ideas that could help get us closer to that goal and make import maps ubiquitous and mindless . Since they were well received, I opened issues for them: I’m linking to issues in standards repos in the interest of transparency. Please don’t spam them, even with supportive comments (that’s what reactions are for). Also keep in mind that the vast majority of import map improvements are meant for tooling authors and infrastructure providers — nobody expects regular web developers to author import maps by hand. The hope is also that better platform-wide integration can pave the way for satisfying the (many!) requests to expand specifiers beyond JS imports . Currently, the platform has no good story for importing non-JS resources from a package, such as styles, images, icons, etc. But even without any further improvement, simply the fact that injector scripts are possible opens up so many possibilities! The moment I found out about this I started working on making the tool I wished had existed to facilitate end-to-end dependency management without a build process (piggybacking on the excellent JSPM Generator for the heavy lifting), which I will announce in a separate post very soon [1] . Stay tuned! But if you’re particularly curious and driven, you can find it even before then, both the repo and npm package are already public 😉🤫 ↩︎ Linking to import maps via an HTTP header ( ?) URLs to bridge the gap between specifiers and URLs Since import maps as an import attribute proved out to be tricky, I also filed another proposal for a synchronous import map API . But if you’re particularly curious and driven, you can find it even before then, both the repo and npm package are already public 😉🤫 ↩︎

0 views

Flight record about MinIO

Flight record about MinIO I wanted to leave a small flight record for my future self about what happened to MinIO. By the time I reread this, it will be old news. That is fine. This is less about the timeline and more about what it reminded me about my own preferences. I recently wrote about a data-first view of systems, where programs are transient and data is the center of gravity.

0 views
underlap Yesterday

Claude code

My son has been using Claude Code at work and telling me how well it seems to perform. Eventually my inquisitiveness got the better of me and I took Claude for a spin. I was surprised how well it did, but also discovered some limitations and how to use it better. I was working on a deadlock of a particular test, so I asked Claude why the deadlock happened. After quite a lot of debugging and analysis, Claude came up with a plausible theory for the deadlock. It managed to code a very reasonable fix too. I got Claude to commit the fix and write a suitable commit log ( commit ). At that stage I asked my friends “Does that make me a bad person?”. It certainly felt uncomfortable to be committing code written by a LLM. The deadlock has not recurred since. A friend asked: That feels like quite a significant moment! And suppose instead of Claude it had been a new human collaborator joining the project for the first time, and you showed them the issue and pointed them at the repo… how impressed or otherwise would you have been if they produced the same patch and analysis in the same amount of time as Claude did? To which I replied “extremely”. Another pointed out that the fix was coded by Sonnet 4.5 and wondered if Opus would have produced a different outcome. Another friend wrote: Wow. I’m very impressed, but also at the same time glad I’ve retired already. I tend to agree. It’s a relief to delegate grunt work to a LLM, but I think some of my skills would start to atrophy. Also, I think it’s good for me to have to do unpleasant or laborious tasks occasionally. Next I asked Claude to improve the throughput of one specific benchmark. It spotted a FIXME of mine which would give an improvement and implemented it (simply, but correctly). It also spotted an issue I knew about, but had temporarily forgotten (needing to remove stale values from a hash map) and fixed that simply and correctly. This broke some tests, as expected, but Claude struggled to rework them until its quota ran out (to be renewed several hours later), so I fixed the tests by hand. If I wanted to anthropomorphise the behaviour, I’d say Claude acted like a capable junior developer who went home with a headache before getting the tests running. On this occasion, I asked Claude to change a public API to achieve a specific change to the implementation (which I detailed). It came up with a plausible plan, although one of the steps was to make an unrelated improvement, so I told it not to do that step. It went through and made changes according to the plan. At least once, it acted like a human in that it ran a build and then fixed up the errors (rather than applying the fixes ahead of time). One of the steps worried me a little because it seemed rather ambitious. It didn’t add any tests to increase confidence in the change. Anyway, I let it proceed. Finally, it ran the tests, fixed some which were failing, and declared success. I ran the tests and one (the most crucial one, given the changes) hung. Claude produced a rambling discourse on what might be causing the test to hang intermittently. It seemed to say that the omitted step was implemented and that this was somehow essential! Maybe the rest of the changes depended on that step in some subtle way? Anyway, Claude hit its quota limit again, so I came back another day and got Claude to debug the intermittent test and tidy up the code in smaller, safer steps. In anthropomorphic terms, this second case was like a mid-level developer who didn’t exercise enough caution when implementing a more complex piece of logic. I guided it through some design changes I’d been mulling over and it spotted problems in the details and found good solutions. The icing on the cake was when I asked it to suggest a new naming scheme for some types and it came up with a good option and described some alternatives it had considered and why the main option was preferable. Another nice touch was when I asked it to update the README to reflect the design goals of the project and how they are implemented - its changes, including fixing a typo of mine in a URL, were really good. This feels like the situation where an experienced colleague joins the team, gets up to speed really fast, and then produces code as good, or perhaps better, than my own. I need to keep a careful eye on what they are doing in case they start to diverge from my design goals [1] , but the additional capability is well worth the cost of supervision. In this experiment I asked Claude to propose and extract some submodules only to find that it had made most of the struct fields , which destroys any pretence of encapsulation. So it seems that the more well-defined the task, the better. Also, it’s clear that, as someone else wrote, “AI doesn’t care”. I asked Claude to suggest possible solutions to the use of on fields. Some of its suggestions were interesting, but I ultimately did most of the work by hand using Claude for specific, laborious tasks. ( Modularisation pull request ) I thought I’d use it to take a crack at a feature I’ve been putting off for ages: shared memory support. I suspected this wouldn’t be too bad, but it would probably be a little laborious making sure the API was functionally equivalent to the shared memory API of . I asked Claude to plan the change. It wanted to submit a PR on to access the thread locals used to (de)serialise shared memory, so I told it to re-plan without changing . Next it planned to (de)serialise shared memory as a byte vector, which would miss the main advantage of using shared memory. So I told it to create a thin wrapper round ’s shared memory type. It re-planned and I let it execute the plan without interruption. It produced code and tests quite quickly and these looked in good shape. When I compared the API with that of , it was missing a couple of methods on the shared memory type, so I asked it to implement these. I had to ask it to write tests, which it did perfectly well even though at least one corresponding method was untested in (so it wasn’t simple copying/massaging that code). I had to manually change the year of the copyright header of the new file, fix one formatting error, and delete the line in the README which mentioned shared memory needed to be implemented. Finally, I got it to describe shared memory in the README API overview and implementation overview. This all took about 1.5 hours whereas doing it by hand would probably have taken me 2-4 times longer. In anthropomorphic terms, it was like directing a capable, energetic, thorough underling who simply had never written a thin wrapper before. With my reduced appetite for simply grinding out code these days, this has been a very pleasant experience. ( Shared memory support pull request ) I had in mind an improvement to the interprocess protocol for . The improvement is to change polling to use on a response channel rather than sending “probe” messages on a forward channel (which could fill up the channel and block). Claude planned this out and generated the code. CI detected an intermittent hang on macOS in an integration test. I asked Claude to debug the hang and, on Linux, it went into “analysis paralysis”. So I switched to macOS so Claude had the option of debugging the test. However, the change of context allowed Claude to come up with a plausible theory of why the test sometimes hung on macOS. This was to do with the behaviour of ( returning instead of in this scenario), so I asked Claude to generate a test to demonstrate the behaviour so I could raise a bug against . It generated a test, but the test did not reproduce the behaviour, so Claude tried re-analysing the behaviour. After running out of quota once or twice and encountering “compaction” (where Claude tries to shed unnecessary context) and after quite a bit of waiting on my part, Claude came up with another plausible theory about the hang: a bug in the code. It proposed a solution to the bug which would have increased file descriptor consumption on Linux [2] , so I suggested a simpler and more efficient fix, which Claude then implemented. CI passed, but since the overall change to the protocol was significant, I first of all reviewed the changes as a pull request and, having found no issues, asked Claude to review the PR carefully. It found a bug in my simpler fix and its implementation. After it had fixed the bug, and improved the code structure in that area, CI still passed, so I ran the benchmarks to make sure performance hadn’t regressed and then merged the branch. In anthropomorphic terms, Claude feels like a really helpful colleague who is prone to go off on tangents and loose track of the bigger picture (e.g. design goals). With appropriate supervision, Claude is saving me a lot of effort and producing excellent code. Some friends who have also been using Claude discussed putting instructions in the repository to guide Claude in future. AGENTS.md seems to be the agent-neutral spot whereas CLAUDE.md can include Claude-specific instructions (and you can use to “include” the other instructions). My AGENTS.md currently has the following contents: and CLAUDE.md simply contains: The “Design goals” section of may not help, but I felt it was necessary after Claude proposed a solution to the hang which cut across one of the design goals (minimising file descriptor consumption on Linux). The first couple of commits including the deadlock diagnosis/fix used Sonnet 4.5 and the later ones seemed to have used Opus 4.6 apart from the protocol deadlock investigation which used Sonnet again (I deliberately switched to Opus for coding the fix and reviewing the PR). Both these models seems capable, but Sonnet seems to consume less quota and is more suited to lighter tasks. I guess my project, like a compiler, particularly lends itself to AI assistance because of the strong typing and the decent collection of docs, tests, and benchmarks. Claude Code is very impressive nevertheless. I continue to be concerned about the ethics of using AI assistance, especially the environmental impact. Tim Bray helpfully observed : At the end of the day, the business goal of GenAI is to boost monopolist profits by eliminating decent jobs, and damn the consequences. This is a horrifying prospect (although I’m somewhat comforted by my belief that it basically won’t work and most of the investment capital is heading straight down the toilet). But. All that granted, there’s a plausible case, specifically in software development, for exempting LLMs from this loathing. He then goes on to explain his reasoning, with which I agree, but I’ll let you read the post rather than reproduce the argument here. This reflection turned out to be prescient given what happened later (see the “Protocol improvement” section). ↩︎ The proposed fix was to associate a sender id. with each SubSender which would mean that the IpcSender would be transmitted every time another SubSender was transmitted from the same source to the same destination. ↩︎ This reflection turned out to be prescient given what happened later (see the “Protocol improvement” section). ↩︎ The proposed fix was to associate a sender id. with each SubSender which would mean that the IpcSender would be transmitted every time another SubSender was transmitted from the same source to the same destination. ↩︎

0 views
Xe Iaso Yesterday

The Unbound Scepter

Nobody warns you about the dreams. Not properly. Yesterday I killed my inner Necron — wrote the whole thing by voice from my hospital bed, felt the deepest peace of my life, went to sleep on whatever cocktail of post-op medications they had me on. Seroquel and Xanax, among other things. Doctors mention "vivid dreams" as a Seroquel side effect like it's nothing. Vivid. That word is doing an extraordinary amount of heavy lifting for what actually happened to me last night. Content warning: this post documents a medication-induced nightmare and gets into some heavy territory around belief systems, vulnerability, and psychological symbolism. These are prescribed medications, not recreational substances. If you're not in the headspace for this right now, it'll be here when you are. Last night I had a dream that was structured enough to have a narrator, a symbolic child heir, and a thesis statement delivered directly to my face before I woke up. I'm not exaggerating. I'm treating this as a trip report because honestly that's what it was. The details are already going fuzzy but the core of it burned in hard enough that I'm typing this up before it fades. Here's what I remember. The dream opened in a mall. Fluorescent lights, tile floors that went on forever, the works. There was an Old Navy ahead of me. But the world had gone full Purge — total lawlessness, everything collapsed — and the Old Navy staff had barricaded themselves inside and were defending it. Like, actively. With the energy of a last stand. My brain decided that in the post-apocalypse, the hill worth dying on was affordable basics. I was naked. Completely exposed, standing in the middle of all this, and I needed to get into that store. Not like "oh I should get dressed" — the desperation was animal-level. Find clothes. Cover yourself. The staff wouldn't let me in. Every step felt like wading through mud. You know that dream thing where your legs just won't work? Thirty feet to Old Navy and I could not close the distance. It was right there . At the center of everything stood a child. A boy, maybe eight or nine, but carrying himself like royalty. In the dream's logic he was the heir to Old Navy — I know how that sounds, but the dream was completely serious about it. He was the successor to this throne. Around his head he had this triangular scepter that worked as both crown and weapon. He kept showing up ahead of me, always blocking the way forward. The scepter was sealed. The triangle was closed — every vertex connected, no way in, no way out. And I just knew what that meant, the way you know things in dreams without anyone telling you: his belief system was a closed loop. Totally self-referencing. Nothing could get in and nothing could escape, and he had no idea, because from inside a sealed triangle there's no such thing as "outside." This maps to what epistemologists call a closed epistemic loop — a belief structure where all evidence gets interpreted through the existing framework, making disconfirmation structurally impossible. Conspiracy theories work this way. So do certain theological traditions. So do some software architectures, honestly. Standing near the child was a black mage. And I mean the Final Fantasy kind — tall, robed, face hidden in shadow. I'd literally been writing about Final Fantasy yesterday so I guess my brain had the assets loaded. But he wasn't threatening. He was... explaining things? Like a tour guide for whatever my subconscious was trying to show me. Very patient. Very calm. Spoke directly to me about what I was seeing. His subject was how belief systems work. He called them principalities of the mind — self-contained little kingdoms where every belief props up every other belief. Contradictions bounce off. The whole thing holds together through pure internal consistency, even when there's nothing underneath it. You can't see the foundation from inside. The child heir was his example — look, here's what a sealed principality looks like when you give it a body and a crown. Movement never got easier. I kept pushing through the mud, the child kept showing up with that sealed scepter catching the light, and the mage just... kept talking. Honestly it was like being in the world's most surreal college lecture. I couldn't take notes. I was naked and covered in dream-molasses. And then everything started dissolving. The mall went first, then the Old Navy fortress, then the chaos outside — all of it pulling apart. But the mage stayed. He looked right at me. Not past me, not through me — at me. And he said: "Your scepter is unbound — do with this what you will." I woke up and lay there for a long time. The contrast hit me while I was staring at the hospital ceiling. The child's scepter was sealed — a closed system that couldn't take in anything new. Perfect, complete, and totally stuck . Mine was unbound. Whatever that meant. I honestly don't know if this is my unconscious mind processing the surgery, the medication doing something weird to my REM cycles, or just the kind of thing that happens when you stare down your own mortality and then your brain has opinions about it. What I do know is that the symbolism was so on-the-nose it felt like getting a lecture from my own subconscious. In chaos magick — which, yes, is a real thing I've read about, I'm not just making this up — there's this concept that beliefs are tools. You pick one up, use it, put it down when it stops being useful. It's not who you are. It's "a person's preferred structure of reality," emphasis on preferred . You can swap it out. Principalities of the mind are what happens when you forget your beliefs are a tool and start treating them like physics. The triangle seals shut. The scepter becomes a prison you can't see from inside. And the part the black mage was so patient about — the really messed up part — is that from inside a sealed principality, everything seems fine. Your beliefs are consistent, reality makes sense, and you have no idea you're trapped because the cage is made of your own assumptions. An unbound scepter is the opposite of comfortable. Your worldview has gaps in it, entry points where new information can come in and rearrange everything. That's scary. But it also means you can actually change, which is more than the heir could say. Wait, so the good outcome here is having a belief system with holes in it? I mean... kind of? A sealed scepter means you never have to doubt anything but you also never grow. An unbound one is overwhelming but at least you can move . The heir was frozen. Perfect and still and going absolutely nowhere forever. Maybe that's why I couldn't move in the dream. Wading through mud, barely able to take a step — but I was taking steps. The heir just stood there. He didn't struggle because he had nowhere to go. His triangle was already complete. "Do with this what you will." That's what the mage said. Not telling me what to do with it. Just... handing me the choice. An unbound scepter doesn't come with instructions. I think the dream was telling me something I already knew. Or maybe reminding me that knowing it once isn't enough — you have to keep choosing to stay open. The triangle is always trying to close. Your scepter is unbound. Do with this what you will. Now if you'll excuse me, I have a hospital discharge to survive and a husband to hug.

0 views