Shellsharks Blogroll - BlogFlock2026-03-05T12:44:44.434ZBlogFlockWerd I/O, Robb Knight, destructured, Molly White, fLaMEd, Aaron Parecki, Trail of Bits Blog, Westenberg, gynvael.coldwind//vx.log (pl), Evan Boehs, James' Coffee Blog, joelchrono, Kev Quirk, cool-as-heck, Posts feed, Sophie Koonin, Adepts of 0xCC, <span>Songs</span> on the Security of Networks, cmdr-nova@internet:~$, Johnny.Decimal, Hey, it's Jason!, Terence Eden’s BlogBook Review: Katabasis by R. F. Kuang ★★★★⯪ - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=682622026-03-05T12:34:44.000Z<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/02/x400.jpg" alt="Book cover featuring an impossible staircase." width="200" class="alignleft size-full wp-image-68264"/>
<p>I'm a fan of R.F. Kuang's books - but this is the first which I've found laugh-out-loud funny. What if your University advisor died and the only way to graduate was to descend into hell and bring him back?</p>
<p>In a terrible sort of way, I'm glad that Kuang had such a miserable time at University. Being able to mine that psychotrauma has led to the brilliant <a href="https://shkspr.mobi/blog/2024/01/book-review-babel-r-f-kuang/">Babel</a> and now the excellent Katabasis. This is <em>almost</em> a love affair to the idea of being the perfect student.</p>
<p>It's also deliciously catty:</p>
<blockquote><p>She had never gotten round to trying Proust, but Cambridge had made her the kind of person who wanted to have read Proust, and she figured Hell was a good place to start.</p></blockquote>
<p>The plot is, almost literally, Alice in Wonderlabyrinth. A metaphysical excursion through logic and fallacy, pausing lightly at revenge, with a quick diversion through intersectional feminism and its limits. Much like the play <a href="https://en.wikipedia.org/wiki/Copenhagen_(play)">Copenhagen</a>, the characters often exist as a way to explore the nature of reality and how it conflicts with academia.</p>
<p>Perhaps it is a smidgen too long, and there are some weird Americanisms which perhaps should have been caught in the edit. A few of the observations about Hell being a writers market or modelled on an essay crisis are a little too on the nose - but, you know what, it is tremendous fun.</p>
📚 Flybot - Kev Quirkhttps://kevquirk.com/flybot2026-03-05T09:34:00.000Z
<div class="card">
<p class="author"><b>by Dennis E. Taylor</b></p>
<p>Physicist Philip Moray is having a good day. He’s chipping away at his big work project. The lunch in the cafeteria is at least edible. And he’s looking forward to his end-of-the-day drink and a soak in the hot tub.</p>
<p>Then, a strange device turns up in his office. A piece of technology he has never seen before–and shouldn’t even exist.</p>
<p>Suddenly, corpses start turning up, eco-activists go on the attack, random people suffer bizarre symptoms. And every time the authorities get a lead, it traces right back to Philip and his colleague, Celia Hunt.</p>
<p>Then, a mysterious caller contacts Philip–and, suddenly, staying out of jail is the very least of his problems.</p>
<p>Apparently, that hot tub’s going to have to wait.</p>
<p><a class="button" href="https://www.goodreads.com/book/show/232957226-flybot">📖 Learn more on Goodreads…</a></p>
</div>
<p>I'm a big fan of <a href="https://kevquirk.com/tag/dennis-e-taylor">Taylor's work</a> but <em>Flybot</em> didn't really hit the mark for me as much as other books from Taylor have. I felt like the story lost its way in the middle; it came together <em>okay</em> in the end, where there was a interesting (but predictable) twist.</p>
<p>Not the best book I've ever read.</p> <div class="email-hidden">
<hr />
<p>Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️</p>
<p>You can <a href="mailto:72ja@qrk.one?subject=%F0%9F%93%9A%20Flybot">reply to this post by email</a>, or <a href="https://kevquirk.com/flybot#comments">leave a comment</a>.</p>
</div>
Persepolis Rising - Joel's Log Fileshttps://joelchrono.xyz/blog/persepolis-rising2026-03-04T22:55:00.000Z<p>I mentioned on my last Weeknotes that I wouldn finish this next week, but against all odds, I ended up finishing the book on the very same day!</p>
<p><em>Persepolis Rising</em> is the seventh book of <em>The Expanse</em> series by James S.A. Corey. And it continues the journey in a rather unexpected way—<em>which got spoiled to me many months ago anyway and it’s not that big of a deal according to <a href="https://benjaminhollon.com">Amin</a> so whatever.</em></p>
<p>We are getting closer to the end of the series, only two more main books to go—and maybe a lot of side stories I’ll check out at some point— so <strong>spoilers about previous books will be present</strong>. You should just give the series a go, I can say it has been absolutely worth it.</p>
<hr/>
<p>Thirty years after the events of the previous books, new colony worlds have flourished, and even if there is struggle here and there, things are looking well. The inner planets and the Belt have become somewhat stable allies, and have managed to get the Transport Union up and running, even if some prejudice persists. Meanwhile, the crew of the <em>Rocinante</em> continues to help out where they can to keep the galaxy at peace.</p>
<p>However, Laconia—the colony world that was claimed by a third of the Martian military—has been working in the background and forming their own nation under Duarte’s rule. Now, they threaten to take over everything Humanity has built thus far. Using ancient alien technology and weaponry developed to be above and beyond everything else, ready to take over and rebuild the colonies under their vision and rule.</p>
<p>This book starts out rather slow I think, although it has some big revelations, about how much happened in the last thirty years as Humanity has expanded to the stars during a period of relative peace, with no big threats and a sense of unity among humans, despite the scale of the space they inhabit by now. We also get a glimpse of what the Laconian Empire looks like from the inside, a regime that has been built with the utmost efficiency, and we even get the perspective of some characters from that side, that give us interesting look to how things are going during the novel.</p>
<p>The Rocinante crew, with Bobbie, Clarissa, Amos, Alex, Naomi and Holden, have grown old, but they are still kicking around, doing side quests and helping out whoever needs it. The Rocinante itself is also old, but it has been kept in check and updated as technology has advanced, an old dog with some nice tricks.</p>
<p>Of course, the sci-fi setting allows for de-aging and similar treatments, a nice way to have a big timeskip while keeping our characters able to flip around and kick the bad guys while looking as cool as ever. They are a family now, but there are some big changes that happen pretty early on, which makes for some interesting conflict between the characters throughout the book.</p>
<p>I especially like the development of Bobbie on this one, but Amos continues to be a favourite, and the struggles he faces during this arc were intense. I was about to cry in one of those chapters, really good stuff.</p>
<p>The stakes on an interplanetary level are huge, and once again, victory is not certain, with things getting worse at every moment. Laconia’s might will prove to be a huge challenge to overcome for our heroes.</p>
<p>The book is written in the same style as ever, keeping me on my toes chapter after chapter, at least during the second half of it, as it takes a bit to pick up.</p>
<p>I must say I found some of the dialogue to feel a little bit repetitive this time around. For example, I think there’s like five or six variations of “this map of space is not true to scalejust to showcase how vast something is, or how small we really are, or something akin. There’s also like three or four “this object is going away but it’s actually us moving”, because of the perspective at zero gravity and the darkness of space (especially in the slow zone). It is nothing bad at all, I think I just noticed it and couldn’t stop doing so later on.</p>
<p>The point of character of the villain is probably the weakest bit. Don’t get me wrong, it is well written, but every single time I just could not help but chuckle and think “how is this guy believing half the things he says?”, which I guess is the point. They are space fascists after all, and even if the ideas are ridiculous, they are also terrifying.</p>
<p>Also, maybe the book is not that slow and it was just me who didn’t commit to it until very late. Here’s a little summary of how my reading progress went:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Progress</th>
<th style="text-align: right">Date</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">Started</td>
<td style="text-align: right">2026-01-17</td>
</tr>
<tr>
<td style="text-align: left">Chapter 3</td>
<td style="text-align: right">2026-02-05</td>
</tr>
<tr>
<td style="text-align: left">Chapter 5</td>
<td style="text-align: right">2026-02-12</td>
</tr>
<tr>
<td style="text-align: left">Chapter 6</td>
<td style="text-align: right">2026-02-17</td>
</tr>
<tr>
<td style="text-align: left">Chapter 7</td>
<td style="text-align: right">2026-02-20</td>
</tr>
<tr>
<td style="text-align: left">Chapter 9</td>
<td style="text-align: right">2026-02-24</td>
</tr>
<tr>
<td style="text-align: left">Chapter 14</td>
<td style="text-align: right">2026-02-26</td>
</tr>
<tr>
<td style="text-align: left">Chapter 21</td>
<td style="text-align: right">2026-02-27</td>
</tr>
<tr>
<td style="text-align: left">Chapter 29</td>
<td style="text-align: right">2026-02-28</td>
</tr>
<tr>
<td style="text-align: left">Chapter 38</td>
<td style="text-align: right">2023-03-01</td>
</tr>
<tr>
<td style="text-align: left">Finished</td>
<td style="text-align: right">2026-03-02</td>
</tr>
</tbody>
</table>
<p>So, as you can see, I had a lot of hiccups during the whole thing, and maybe if I was better at sticking to it like I did during the last few days, I would have finished this in less than a week.</p>
<p>In any case, this was a very great way to start the last trilogy of this book series, and I am extremely hyped to pick up the next book, once everyone in my Book Club catches up. I won’t say the last person missing, out of respect, but I hope they get it over soon. You know who you are, evil.</p>
<p>
<a href="mailto:me@joelchrono.xyz?subject=Persepolis Rising">Reply to this post via email</a> |
<a href="https://fosstodon.org/@joel/116173393745649151">Reply on Fediverse</a>
</p>Another New Lick of Paint - Kev Quirkhttps://kevquirk.com/another-new-lick-of-paint2026-03-04T18:42:00.000Z
<p>Around a month ago <a href="https://kevquirk.com/ive-moved-to-pure-blog">I switched this blog to Pure Blog</a>, at the same time, I decided to simplify the design and give it a new lick of paint. Here's what it looked like:</p>
<p><img src="https://kevquirk.com/content/images/another-new-lick-of-paint/feb-2026-design.webp" alt="feb 2026 design" /></p>
<p>It was <em>okay</em>. But I've done the <code>box-shadow</code> thing before, and I really wanted something different. The problem was, I didn't know what I wanted.</p>
<h2>Inspired</h2>
<p>My wife and I recently went away for the weekend. While away, we stopped off at a lovely little coffee shop where they served us water and a pot of tea from these beautifully coloured pots.</p>
<p><img src="https://kevquirk.com/content/images/another-new-lick-of-paint/pots.webp" alt="pots" /></p>
<p>The mustard yellow and the steel blue are just beautiful; they work so well together, and I immediately decided I wanted to use this kind of palette for my next website design.</p>
<p>Since Monday I've been working on the re-design (something that's <em>really</em> simple to do with <a href="https://pureblog.org">Pure Blog</a>). it's now ready and I've launched the new site this evening. Here's what it looks like now:</p>
<p><img src="https://kevquirk.com/content/images/another-new-lick-of-paint/light.webp" alt="light mode" />
<em>Light mode</em></p>
<p><img src="https://kevquirk.com/content/images/another-new-lick-of-paint/dark.webp" alt="dark mode" />
<em>Dark mode</em></p>
<p>I thought about using the mustard colour for the entire background, but since this is a blog, reading experience is very important, and I felt I was straining my eyes when reading in full mustard mode. So I toned it down to this nice cream colour, and stuck with mustard for the header and footer only. While I was there I also got rid of the <code>box-shadow</code> effect to simplify the site header even more.</p>
<p>I have to say, I'm really happy with the result.</p>
<p>There's bound to be some little bug or caching issues here and there, which I'll mop up as I discover them. If you find an issue, please drop me an email or leave a comment, and I'll get it sorted.</p> <div class="email-hidden">
<hr />
<p>Thanks for reading this post via RSS. RSS is ace, and so are you. ❤️</p>
<p>You can <a href="mailto:72ja@qrk.one?subject=Another%20New%20Lick%20of%20Paint">reply to this post by email</a>, or <a href="https://kevquirk.com/another-new-lick-of-paint#comments">leave a comment</a>.</p>
</div>
Night time; walking - James' Coffee Bloghttps://jamesg.blog/2026/03/04/night-time-walking/2026-03-04T18:33:47.000Z
<blockquote>i'll spend my whole life looking for the next best thing<br/>but when I finally find it, i’ll be too busy looking<br/>for the next best thing</blockquote><p>I had spent half of the day travelling and the other half looking at art. Whenever I am going anywhere, I like to arrive as early as I can and either walk around or go to an art gallery; ideally, I like to do both. After all the galleries had closed and I had eaten dinner, I walked for an hour or two as the sun set. I had spent enough time indoors; I needed to exercise my legs.</p><p>I love walking around central London, especially down the Thames. There is a nice path on the south side of the river that takes you past many wonderful places. You can see skateboarders in their element in a skate track, which is next to a cinema; across the river you see the grand Somerset House, home to the Courtauld Gallery. The more you walk, the more you see: cathedrals and parliament and bridges and water.</p><p>I was walking over a bridge and admiring the colours of the city after the sun had set. Pink neon lights coming from the bridge I was on cast beams of light in front of me. The clock of Big Ben shone bright. In the heart of so much beauty – and so close to many stories – it was not the light but a few words that caught my eye. As I was walking, I saw a message written on the pavement.</p><blockquote>i'll spend my whole life looking for the next best thing<br/>but when I finally find it, i’ll be too busy looking<br/>for the next best thing</blockquote><p>“What’s next?” I ask myself that question a lot. What is the next thing I am going to make? What will I do next? It is little wonder that I have felt lost lately; if I am worried about what’s next, I lose sight of what is in front of me. Despite the size and scale of London relative to where I call home, I didn’t feel lost at any point on my trip. I didn’t have time. I was walking and listening and talking and studying art. I was following familiar paths and going on detours and listening to my feet. <em>I am here.</em></p><p>With the message written on the pavement in mind, I decided to focus on what I could see: all of the beautiful buildings around; the calm flow of the evening river on a spring day. I admired the cityscape. I turned around so that I could see as many perspectives as I could from where I was standing. <em>I am here.</em></p><p>I continued on with my walk. London is beautiful in the evening. I ended my day watching the city around me. I love to watch and study. I started the next day with a walk by the same river, a day on which I had plans – a day for which I had been looking forward for weeks. And as the weekend went on, I found myself with more and more answers to: what’s next? Among them: I don’t need to push to move forward: there is so much for me to learn from where I am.</p><p><em>The writing on the bridge was signed </em><a href="https://www.instagram.com/beakandsqueak/?hl=en" rel="noreferrer"><em>@beakandsqueak</em></a><em>, who has reportedly </em><a href="https://www.swlondoner.co.uk/entertainment/23102025-meet-the-anonymous-street-artist-helping-londoners-make-light-of-their-complicated-emotions" rel="noreferrer"><em>written hundreds of messages in chalk across London</em></a><em>. I am sincerely grateful that they took the time to write a message for others to enjoy.</em></p>
<a class="u-mention" aria-hidden="true" href="https://www.instagram.com/beakandsqueak/?hl=en"></a>
Guitar; sunset - James' Coffee Bloghttps://jamesg.blog/2026/03/04/guitar-sunset/2026-03-04T18:12:02.000Z
<p>The days are getting longer and brighter. The bite of the winter air is being replaced by a delicate breeze. It feels like Spring is here.</p><p>I have been trying to play my guitar every day, usually before I eat dinner. Over the last week, I have noticed that the time I play the guitar coincides with the setting sun. Today, I stopped playing a bit early so I could admire the orange glow of the sun on the horizon. <em>I love watching sunsets.</em> I keep going back to the window to look at all the other colours in the sky: the faint pink hue where there was only half an hour ago a vibrant orange, the light blues.</p><p>Looking at the hills now, I notice they have a hint of blue, too. A couple just hugged outside as I stand with my laptop arches on one knee, writing about what I see. When you look outside you never know what you are going to see. The couple are now walking together. I love moments when people get together.</p><p>Anyway: the hills have a hint of blue. Like some paintings I have studied. I didn’t know why until recently. It turns out there is a name for this phenomena: <a href="https://en.wikipedia.org/wiki/Aerial_perspective">aerial perspective</a>, where the “colours of the object also become less saturated and shift toward the background colour, which is usually bluish”. I have never thought about how the hills can really take on a blue hue in the distance, and how that is mirrored in art. Studying art is giving me new lenses through which to see the world; new words to explain what I see.</p><p>I have been practicing the guitar for a few months now. Since the beginning I have hoped that I could sing along to a song. Over the last few weeks I have been trying little by little and, this week, I have finally been able to sing along with a few songs. I feel my right hand becomes more automatic when I am strumming. I am starting to notice that I can find the rhythm of a song. For all the guitar players out there, the DUDU DUDU DDU and DD UU DU strumming patterns are the easiest for me to sing along to right now. </p><p>It feels great to be able to sing along to songs I love and play them at the same time. I am not a good singer, but I am having fun.</p><p>The days are getting longer and brighter. I see the early stages of the sun rise and can watch the sun set. I see colours I forgot the sky could have. I think about how those tones are mirrored in art. The vibrant colour of the orange sun this evening reminds me of the colour of the sun in Monet’s <em>Impression, Sunrise</em>, the first painting to be known as Impressionist. The colours are beautiful.</p>
22.00.0187 Post-incident review - Johnny.Decimalhttps://johnnydecimal.com/22.00.0187/2026-03-04T17:56:32.000Z<h1 id="post-incident-review">Post-incident review</h1>
<p>Yesterday I discovered that I had leaked 3,638 email addresses by uploading them to a public GitHub repository.</p>
<p>Here's what happened, how it happened, what I did about it, and what I'm doing to make sure it can't happen again.</p>
<h2 id="tldr">TL;DR</h2>
<p>This post will be long, so here's the essential stuff if that's all you care about.</p>
<p>Yesterday morning (2026-03-03 06:00 -- all times in this post are UTC) I was alerted by email and private message that someone's unique email address, that they had only ever used on my services, had received a phishing email purporting to be from PayPal.</p>
<p>There's only one way for this to be possible: it meant that I had allowed the address to be stolen. I acknowledged this with a <a href="https://johnnydecimal.com/22.00.0185/">blog post</a> at 06:46, requesting that people let me know if they were affected.</p>
<p>Through the day I received, or could infer from my own data, 17 addresses that either did, or did not, receive the phishing email.</p>
<p>Analysis of these 17 data points led me to the realisation that I had uploaded a folder full of text files containing email addresses to a public GitHub repository. This made them visible to anyone who cared to go looking. I confirmed this theory at 18:00 and immediately made the repository private. I acknowledged this with a <a href="https://johnnydecimal.com/22.00.0186/">blog post</a> at 18:18.</p>
<p>The first upload of 1,650 addresses occurred on 2024-10-08. Further updates were uploaded through 2025. The final number of addresses in the repository was 3,638. Because I don't know when the data was scraped from GitHub, I can't be sure which of those addresses was harvested. My assumption must be that they all were.</p>
<p>I am deeply sorry. I strive every day to be an exemplar of 'the good Internet'. In this instance, I have failed you quite miserably.</p>
<h3 id="how-to-determine-if-your-address-was-leaked">How to determine if your address was leaked</h3>
<p>Immediately after this post has been published I will email the 3,638 addresses that were leaked.</p>
<ul>
<li>From: Johnny 'Decimal' Noble <<a href="mailto:hello@johnnydecimal.com">hello@johnnydecimal.com</a>></li>
<li>At: around 2026-03-04 18:00 UTC</li>
<li>Subject: Important: your email address was exposed [D25.14.44]</li>
</ul>
<p><strong>If you receive this email then your address was leaked</strong>.</p>
<p>You can also check if you received the phishing email:</p>
<ul>
<li>From: PayPal Security <no.con**star@ca**a.cl></li>
<li>At: around 2026-03-03 05:30 UTC</li>
<li>Subject: Please confirm your identity</li>
</ul>
<p><strong>If you receive this email then your address was leaked</strong>. (Check your spam folder: many providers correctly identified it as a phishing attempt.)</p>
<p><strong>If you do <span style="text-decoration: underline;">not</span> receive either of these emails then your address was not leaked</strong>.</p>
<h3 id="was-any-other-data-leaked">Was any other data leaked?</h3>
<p>Like names, addresses, dates of birth, passwords, or access to accounts?</p>
<p>No. The only data leaked was a list of email addresses in a text file.</p>
<h3 id="whats-the-impact-of-the-leak">What's the impact of the leak?</h3>
<p>The email address that was leaked will receive spam and phishing attempts.</p>
<p>To be clear, your <strong>account</strong> has not been compromised. Only your email <strong>address</strong> has been made public. You do not need to change your password (assuming it is already unique -- see <a href="#what-can-you-do">What can you do?</a> at the end of this post).</p>
<h2 id="full-timeline">Full timeline</h2>
<ul>
<li>06:00
<ul>
<li>Leak notification received.</li>
<li>Incident D25.14.44.2026-03-03 created.</li>
</ul>
</li>
<li>06:46
<ul>
<li><a href="https://johnnydecimal.com/22.00.0185/">Public informed of breach</a>.</li>
</ul>
</li>
<li>08:16, 08:32, 08:47, 09:40, 10:43, 11:51, 12:55, 14:02, 14:43, 15:31
<ul>
<li>Data received from affected users helped me to build the picture.</li>
<li>I'll explain below why this took so long.</li>
</ul>
</li>
<li>18:00
<ul>
<li>I realised what it was and used local data to confirm.</li>
<li>The repository was made private.</li>
</ul>
</li>
<li>18:18
<ul>
<li><a href="https://johnnydecimal.com/22.00.0186/">Public informed of cause</a>.</li>
</ul>
</li>
</ul>
<h3 id="how-it-happened">How it happened</h3>
<p>Here's <em>why</em> I had a folder full of your email addresses, and how they ended up on GitHub.</p>
<p>Over the years I've used a variety of 3rd party platforms to deliver websites and services, as well as hosting a public email list.</p>
<ul>
<li>Buttondown
<ul>
<li>Used to host the mailing list from 2019–2024.</li>
<li>Allowed users to opt-in to email marketing.</li>
<li>Users hold an account of sorts; while you don't have a password, the platform records your email address.</li>
</ul>
</li>
<li>Netlify
<ul>
<li>Used to host johnnydecimal.com and jdhq.johnnydecimal.com from 2019–current.</li>
<li>Users do not hold an account at Netlify: it's an infrastructure service only.</li>
</ul>
</li>
<li>Gumroad
<ul>
<li>Used to sell the Workbook from 2023–2024.</li>
<li>Allowed users to opt-in to email marketing.</li>
<li>Users held an account at Gumroad.</li>
</ul>
</li>
<li>Thinkific
<ul>
<li>Used to sell various products from 2023–2025.</li>
<li>Users held an account at Thinkific.</li>
</ul>
</li>
<li>Shopify
<ul>
<li>Used to sell various products from 2024–2025.</li>
<li>Allowed users to opt-in to email marketing.</li>
<li>Users held an account at Shopify.</li>
</ul>
</li>
<li>Stripe
<ul>
<li>Used to process payments from 2024–current.</li>
<li>Users hold an account of sorts at Stripe: you can't log in, but they hold a record of transactions linked to your email address.</li>
</ul>
</li>
<li>PayPal
<ul>
<li>Used to process payments from 2024–current.</li>
<li>Users may hold an account at PayPal.</li>
<li>It's also possible to check-out as a guest, but in any case your email address is recorded.</li>
</ul>
</li>
<li>Listmonk
<ul>
<li>Used to host the mailing list from 2025–current.</li>
<li>Allows users to opt-in to email marketing.</li>
<li>Users hold an account of sorts; while you don't have a password, the platform records your email address.</li>
<li>The link at the bottom of every email allows you to unsubscribe (in which case your email address is retained) or delete your data entirely.</li>
</ul>
</li>
<li>PikaPods
<ul>
<li>Used to host Listmonk from 2025–current.</li>
<li>Users do not hold an account at PikaPods: it's an infrastructure service only.</li>
</ul>
</li>
<li>Amazon Simple Email Service (SES)
<ul>
<li>Used to send emails from 2025–current.</li>
<li>Users do not hold an account at Amazon: it's an infrastructure service only.</li>
</ul>
</li>
<li>Clerk
<ul>
<li>Used to host JDHQ user accounts from 2025–current.</li>
<li>Users hold an account at Clerk.</li>
</ul>
</li>
</ul>
<p>If this sounds like a nightmare, it's because it is. But this is the reality of running a small online business: you stitch together that business based on the services available to you at the time. This is a factor of features, cost, and experience. As your business grows, you move between platforms.</p>
<p><strong>To be explicit: none of this is the fault of any of these platforms. I list them all merely to demonstrate the range of stuff one has to deal with.</strong></p>
<p>The reality of running this type of business is that you spend a <em>lot</em> of time consolidating user data from these services. Why is <em>this person</em> in this data set and are they the same person as <em>this person</em> in that data set? You do this so you can mail the right people the right information; send subsets of people offers that are only relevant to them; migrate user accounts from old platforms to new platforms.</p>
<p>As a small business with limited resources there's only one practical way to do this analysis: Excel. In a bad month I might spend 50% of my time 'mashing' data like this. I hated having to do it, and eliminating it was a very strong driver in my building JDHQ: because now you have a single account, forever. No more mashing of CSV files exported from half a dozen platforms.</p>
<p>(Ironically, this leak is partially a result of my very, very strong desire to never send anyone an email that they don't want. I've spent dozens of hours over the last few years meticulously poring over and cross-referencing this data, taking pains to ensure that someone who opted out on <em>this platform</em> didn't get opted back in on <em>that platform</em>. Had I not bothered, some of this data might not have been on my laptop. C'est la vie.)</p>
<h3 id="so-we-have-a-folder-full-of-csv-files">So we have a folder full of CSV files</h3>
<p>That's where we are in the story: I have a folder full of CSV files from these various platforms that I've been using to consolidate and migrate accounts, and to send email directly from my laptop via Amazon SES.</p>
<p>So how did they end up on GitHub? Sheer stupidity.</p>
<p>This repository started on 2024-01-10 as an intentionally-public archive of emails sent to the mailing list. It contained 3× text files.</p>
<p>The problem started on 2024-10-08 when I started to use the same folder to store the output from these CSV files.<sup><a href="#user-content-fn-script" id="user-content-fnref-script" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup> Forgetting that the linked repository was public, I committed these files and 'pushed' them to GitHub. At this point they were available publicly.</p>
<h3 id="why-this-gitgithub-thing">Why this git/GitHub thing?</h3>
<p>It's natural to use <code>git</code> -- which is software independent of GitHub, the website -- to manage a dataset like this. It gives you version control, which is really useful. If you mess up, you can just 'roll back' to a previous state.</p>
<p>Using <code>git</code> locally isn't the problem. Not realising that the linked GitHub repository is public and pushing to it was the fatal mistake. I'll address this below.</p>
<p>From 2024-10-08, this folder, which lives at <code>~/dev/amazon-ses</code> on my laptop, continued to be used as a place where I stored lists of email addresses so that I could send email via Amazon SES. Every time I did that, I committed the changes and pushed them to GitHub. And so by yesterday, the repository held 3,638 unique email addresses.</p>
<h3 id="my-own-password-hygiene">My own password hygiene</h3>
<p>So that I don't need to make the point below with regards to each specific service, I'll make it here.</p>
<p>I have exclusively used 1Password for password management since 2009. All of my passwords are unique and they exceed all modern standards for entropy. Where 2FA is an option I always enable it.</p>
<p>It was, at least, nice to know from the start that this leak wasn't the result of bad password management.</p>
<h3 id="my-secret-key-hygiene">My 'secret key' hygiene</h3>
<p>Separate from passwords, developers of sites like mine have 'secret keys' that are used by servers and services to talk to each other. From JDHQ, for example, you can opt-in to product notification emails. This is possible because the service that serves JDHQ, Netlify, has the secret key for Listmonk and can talk to it directly via the software I've written. If you have the secret key for a service, you can read all of the data contained therein.</p>
<p>I was already planning an article detailing the steps I take to secure these keys, so I'll just note here that they're also all stored in 1Password, and that I had already taken what I believe to be extraordinary lengths to secure them against attack. More to follow.</p>
<h3 id="listmonk-and-pikapods">Listmonk and PikaPods</h3>
<p>I 'self-host' my mailing list using Listmonk hosted on a PikaPod.<sup><a href="#user-content-fn-self-host" id="user-content-fnref-self-host" data-footnote-ref="" aria-describedby="footnote-label">2</a></sup> At 06:31 I identified that the Postgres instance used by Listmonk was open for login using a public console. This isn't enabled by default: I had turned it on a few months earlier so that I could connect directly to the database using client software on my Mac.</p>
<p>Forgetting to disable that access was definitely a mistake -- see action 4, below -- but the risk seemed low. The username and password are set by PikaPods and both were secure: the username not being <code>admin</code> or similar, and the password being a 24-character string. Checks of the console software, Adminer 5.4.2, showed no vulnerabilities.</p>
<p>For these reasons, I dismissed the possibility of a leak via this route. Because I was so sure that this wasn't the cause, I didn't email PikaPods until 15:36. Finally doing so, I asked them if there were any logs for this console endpoint that might be useful.</p>
<p>Their reply just 45 minutes later was stunningly helpful, clearly written by a caring human. I could not have recommended them more <em>before</em> this happened, and yet here we are, my endorsement stronger than ever. A superb service, utterly without fault.</p>
<p>At this point (16:13) I hadn't positively eliminated this as the cause, but it seemed vanishingly unlikely.</p>
<h3 id="buttondown">Buttondown</h3>
<p>Early data supported a theory that Buttondown's service had been compromised. As a reminder, they hosted my mailing list from 2019–2024. So it's not unusual that there was a 1:1 match between leaked email addresses. I mailed their support at 08:57 emphasising:</p>
<blockquote>
<p>"This is NOT an accusation -- I'm trying to figure this out myself. It's purely FYI, and I genuinely hope for you that I'm wrong."</p>
</blockquote>
<p>– thinking that, if a leak had occurred, their support might appreciate the data.</p>
<p>Through the day I continued to receive data points, none of which disproved this idea. This analysis was basic science at work: build a hypothesis, collect data, see if data supports hypothesis.</p>
<p>Of course good science is about a <em>falsifiable</em> hypothesis, and at 15:31 I was made aware of 3× addresses that had received the phishing email that were <em>not</em> in my Buttondown exports. It was a relief to rule them out as a cause and I notified them immediately.</p>
<p>Again, I can't sing the praises of a company enough. Anita from Buttondown support felt like a friend yesterday, keeping in touch even after I informed them of this finding. If you need an email newsletter, use Buttondown. They're truly good people.</p>
<h3 id="how-i-came-to-the-answer">How I came to the answer</h3>
<p>Around 16:30 we went for our usual end-of-the-day walk. Still not knowing the cause, I replayed all of this to Lucy. Thoughtful questions followed and, via this conversation, the thought occurred to me. Back to science, this is Occam's Razor in a nutshell: given all possibilities, the simplest should be considered the most likely.<sup><a href="#user-content-fn-occam" id="user-content-fnref-occam" data-footnote-ref="" aria-describedby="footnote-label">3</a></sup></p>
<p>The simplest possibility being that I, as a holder of all of this data on my laptop, committed it to a public repository. Getting home, this was confirmed at 18:00.</p>
<h3 id="a-note-on-the-data-sources-involved">A note on the data sources involved</h3>
<p>You might be on this list despite having never signed up for my mailing list. For example, hundreds of email addresses from JDHQ members are impacted. Those addresses aren't on the public list, because I never sign you up without your explicit opt-in.</p>
<p>These addresses are in the data because I used the leaked scripts and Amazon SES to send transactional emails as well as marketing emails to the public list. Similarly, addresses from previous platforms may be present.</p>
<h2 id="lessons-learned">Lessons learned</h2>
<p>Looking out of the window earlier this week I saw a fire engine, sirens blaring, scream up behind a learner driver. <em>Should be part of your driving test</em>, I thought. Because you can't truly be prepared for the panic induced by sirens a metre behind you until it happens.</p>
<p>In a way, I'm glad this happened. Without trying to minimise the event, it's fair to say that on the spectrum of security and data leaks, this is about as benign as it gets. Better that this happens now when I can learn from it, than a much worse event happens later.</p>
<p>Because if this hadn't happened, I would have spent the day developing JDHQ, where you'll soon have the ability to store your own notes, and create your own IDs.<sup><a href="#user-content-fn-jdhq-data" id="user-content-fnref-jdhq-data" data-footnote-ref="" aria-describedby="footnote-label">4</a></sup> It is impossible to convey the depth of responsibility I feel for this data. I lie awake at night thinking about how to keep it secure. (An enjoyable problem to solve, to be clear.)</p>
<p>Like I said above, I've already been planning a post addressing this data and the measures I'll take to protect it. So here let's just talk about what I learned yesterday.</p>
<h3 id="if-you-dont-have-it-you-cant-lose-it">If you don't have it you can't lose it</h3>
<p>I can't stress enough that I do not want your personal data. Having it means having responsibility for it: and then look what happens.</p>
<p>You may notice that I don't ask for your name when you sign up for JDHQ. Requiring a name is an option at Clerk, where your user account is held. I turned it off. You may notice that I don't ask for your address when you make a purchase. This is an option at Stripe, who processes your payment. I turned it off.</p>
<p>Still, in diagnosing this issue yesterday I realised how much data I have on this laptop. Again -- see above -- this is largely unavoidable. I run a business, I need to manage the business' data. For example, every quarter I need to download my transactions for tax reporting.</p>
<p>But I can definitely change my behaviour.</p>
<h3 id="action-1-make-customer-data-more-difficult-to-access">Action 1: make customer data more difficult to access</h3>
<p>You might think I'd be safer just deleting it, but this data proved very useful in troubleshooting yesterday's issue. Without it I'd have been blind. So I'd rather not <em>delete</em> it; I don't think there's a problem that this would solve.</p>
<p>The problem to solve is that having this stuff sitting in folders on my laptop is too loose.<sup><a href="#user-content-fn-laptop" id="user-content-fnref-laptop" data-footnote-ref="" aria-describedby="footnote-label">5</a></sup> It's too easy for something to leak; too easy for me to think of these files in the same way that I think of all my other files. Instead, I need to be acutely aware that when I'm interacting with them that I'm in <em>some special place</em>. I need to be on high alert.</p>
<p>I have created an APFS encrypted disk image and moved all existing customer data to it. It is mounted on-demand. The password is in 1Password and requires a manual copy/paste: I won't store it in my Keychain, so the disk can't ever mount without my explicit action.</p>
<p>Mounting it will forever recall this incident, and I'll be vigilant. I'll do what I need to do and unmount it. There's no chance that I'll make the mistake of pushing something in there up to the cloud.</p>
<h3 id="action-2-only-download-what-i-need">Action 2: only download what I need</h3>
<p>When I download data from these platforms -- say that quarterly tax analysis from Stripe -- my tendency has been to be lazy, and grab everything. As in, choose all the columns, download everything offered.</p>
<p>Because if you're not exactly sure what you need, it's more convenient to have everything to hand than to have to go back and get what you missed.</p>
<p>From today, I'll only download the specific data that I need to do the job. For Stripe's tax analysis, that might be as minimal as the transaction ID, amounts, and the country of purchase. Your name and email address isn't a factor in my reporting a quarterly sales tax total to the Australian Tax Office -- so why even request that in the export?</p>
<h3 id="action-3-proactively-delete-accounts">Action 3: Proactively delete accounts</h3>
<p>I still had a Buttondown account that I wasn't using. It still contained thousands of email addresses.</p>
<p>It, and its associated data, has been deleted. If I think of any other similar accounts, I'll delete them.</p>
<h3 id="action-4-reminders-to-disable-open-services">Action 4: reminders to disable open services</h3>
<p>While it proved not to be relevant, I was disappointed to find that I'd left the Listmonk Postgres database console access enabled. This was an unnecessary risk and happened because I simply forgot to disable it when I was finished.</p>
<p>In the future, if I open up anything like this -- which, again, is going to be necessary to run a business -- I'll set a timed reminder for myself to close it when finished.</p>
<h3 id="action-5-github-is-not-a-backup-service">Action 5: GitHub is not a backup service</h3>
<p>I have a tendency to think of GitHub as a useful backup service. Do a quick <code>git push</code> and now the precious data that I just spent all day massaging into shape is copied to the cloud.</p>
<p>This isn't what GitHub is for! Never again, for any data.</p>
<h3 id="action-6-compliancereporting">Action 6: Compliance/reporting</h3>
<p>Thanks to my Discord for flagging the possibility that I might need to register this breach with various national authorities.</p>
<p>I've investigated a few, and this event is below the reporting threshold. GDPR says that I need to keep internal breach logs and learn from the event, which I was already doing. If you're aware of a more strict requirement from your local authority, <a href="mailto:hello@johnnydecimal.com">let me know</a> and I'll gladly comply. Obviously I can't check them all.</p>
<h2 id="what-can-you-do">What can you do?</h2>
<p>You, as in the reader. What can <em>you</em> do to make yourself more safe online?</p>
<p>Lucy and I have been talking for at least a year about producing a (free) video series addressing the basics of online hygiene. We've moved that idea to the top of the list and will start working on it immediately.</p>
<p>I need to get this post published so I won't go into details here, but the two things you can do to put yourself above 99% of everyone else are:</p>
<ol>
<li>Use a password manager. Allow it to generate random passwords for you, different for every site. <strong>This isn't optional in 2026</strong>.<sup><a href="#user-content-fn-coincidentally" id="user-content-fnref-coincidentally" data-footnote-ref="" aria-describedby="footnote-label">6</a></sup></li>
<li>Use unique email addresses for each service that you sign up for. This is more difficult, and introduces complexity.</li>
</ol>
<p>We'll cover both of these in the course.</p>
<h3 id="questions">Questions?</h3>
<p>If you have any questions please post them <a href="https://forum.johnnydecimal.com/t/email-address-leak/2886">at the dedicated forum thread for this incident</a>.</p>
<p>If you run a small business and need help: we are here. This stuff is <strong>difficult</strong>: I messed up and I'm supposed to be an expert. Please ask and we will help you.</p>
<p><strong>End of incident review.</strong></p>
<hr>
<p><em>100% human. 0% AI. Always.</em></p>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-script">
<p>More accurately, the leaked data took the form of lists of email addresses in a <code>.sh</code> script, which called the <code>aws sesv2</code> command to send an email. For the sake of simplicity I'll continue to refer to 'CSV files' in the main story; the data is identical, the only difference being a file extension. <a href="#user-content-fnref-script" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-self-host">
<p>Acknowledging that this is a stretch of the definition of 'self-hosting'; the point being that PikaPods provides me the raw instance, and that configuration and management of this instance is my responsibility. They sit between PaaS and SaaS. <a href="#user-content-fnref-self-host" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-occam">
<p>I know that's a common mis-reading of Occam's Razor, which actually states that the theorem that introduces the fewest new elements should be considered the most likely. Close enough. <a href="#user-content-fnref-occam" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-jdhq-data">
<p>One person has already written me asking why I think storing user data in JDHQ is a good idea. This isn't the post to prosecute that question but briefly: I'm building features that <em>I want</em>. I think you'll find them useful too. If you never want to use them … just don't. <a href="#user-content-fnref-jdhq-data" data-footnote-backref="" aria-label="Back to reference 4" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-laptop">
<p>Noting that I don't consider the laptop itself to be an attack vector. It requires my password immediately after being locked, has FileVault full-disk encryption, and has no open Internet ports. <a href="#user-content-fnref-laptop" data-footnote-backref="" aria-label="Back to reference 5" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-coincidentally">
<p>Coincidentally, a friend of Lucy's was hacked last week. They got her Microsoft OneDrive account and everything in it. She's in the process of getting new passports and drivers licences. A true nightmare. Why? Shared passwords. <strong>Your password must be unique</strong>. <a href="#user-content-fnref-coincidentally" data-footnote-backref="" aria-label="Back to reference 6" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>Offline mode - James' Coffee Bloghttps://jamesg.blog/2026/03/04/offline-mode-2/2026-03-04T15:15:43.000Z
<p>My blog has an <a href="https://jamesg.blog/offline">offline mode</a> that lets you view articles you have previously read on my website. This mode allows you to read something on my website even if you don’t have an internet connection. If the page you want to view has not been cached, you will see a custom page that lists articles you can read:</p><img alt='A page with the heading "You Are Offline" with a list of articles and pages that can be viewed offline.' class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/offlinemode.png" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/offlinemode.png 600w, https://editor.jamesg.blog/content/images/2026/03/offlinemode.png 804w"/><h2 id="how-it-works">How it works</h2><p>My offline mode works using a service worker (<a href="https://jamesg.blog/service-worker.js">see code</a>) that is based on Jeremy Keith’s examples of service workers (<a href="https://gist.github.com/adactio/fbaa3a5952774553f5e7">example one</a>, <a href="https://gist.github.com/adactio/4d588bb8a65fa11a3ea3">example two</a>; NB: I may be missing some examples; See also: <a href="https://adactio.com/journal/13540">Minimum viable service worker</a>). Jeremy wrote a book that documents how you can add offline support to your website: <a href="https://goingoffline.adactio.com/">Going Offline</a>. I haven’t read this book, but all the code snippets and blog posts that Jeremy has posted has helped me get to something that works for me.</p><p>When you visit my website, a service worker is registered. This service worker maintains a cache using the JS Cache API. When the service worker is first registered, a selection of articles I have written are automatically cached. This means that if you only visited my website once or twice, you would still have something to read. <a href="https://editor.jamesg.blog/offline">My offline page</a> is also cached.</p><p>This service worker intercepts web requests to my website. If I am reading the code correctly (it has been years since looked at this, and my work is largely based on Jeremy’s examples), a <code>fetch</code> request is made to my site first. If the request is successful, the result is cached for later. If the request fails and there is a cached version of the page available, the cached page is returned. If the user is offline and no cached page is available, the <code>/offline</code> page is displayed. [1]</p><p><a href="https://editor.jamesg.blog/offline">My offline page</a> lists articles and web pages that have been cached in your browser, listed in descending order by the date the URL was added to the cache. This allows you to see what is available to read while you are offline.</p><p>Looking at this page now, I think I want to separate the list of articles available for offline reading into two lists: a list of blog posts and a list of pages. I may work on this at some point.</p><p>The reason I am so reliant on Jeremy’s examples is that service workers aren’t the easiest to work with. I am not an expert on service workers; I have used them sparingly, and I can't say what I have follows best practices since it is a few years since I am not up to date on service workers. I encourage you to do your own reading and experimentation while playing around with them. I found working from examples to be the easiest way to get something that worked.</p><p><a href="https://jamesg.blog/service-worker.js" rel="noreferrer">You are free to copy mine in its entirety</a> if you would like, as it is licensed under the same CC0 1.0 Universal license as Jeremy’s original work. You’ll need to update the list of URLs to add to the cache to be posts that exist on your website, and update the <code>/offline</code> link to wherever you end up storing your offline page. You will also need to add the registration code to every page on your site:</p><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">script</span><span class="p">></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="s1">'serviceWorker'</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="nx">navigator</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">'load'</span><span class="p">,</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">navigator</span><span class="p">.</span><span class="nx">serviceWorker</span><span class="p">.</span><span class="nx">register</span><span class="p">(</span><span class="s1">'/service-worker.js'</span><span class="p">);</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="p">}</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
<h2 id="experience">Experience</h2><p>I love having an offline mode.</p><p>I think I have only used the offline mode once when I was at an IndieWeb event, sitting in a cafe with my WiFi off. I was writing a blog post and had my WiFi off in part because the connection was bad in the cafe and also in part because I wanted to focus on writing. I needed to consult a page on my website though. Offline mode lets me do that.</p><p>While I haven't used the feature much, given how much I consult my website on a day to day basis it is reassuring that I can access some of it offline (ideal if I am using my phone).</p><p>I have been working on a new project for <a href="https://amie.jamesg.blog/">sharing contacts at events</a> that stores all data locally. For this, too, I am using a service worker to add an offline mode. This means I can use the website even if I have variable or no connectivity.</p><p>Designing an offline mode has several parts: the technical infrastructure behind it (in this case, the service worker), the offline mode experience, and, in more complex cases, additional technical decisions that need to be made if a site has an offline mode (i.e. synchronisation for applications that need to send data back to a server). For a blog like this, the service worker does most of the heavy lifting, and my <a href="https://editor.jamesg.blog/offline">offline page</a> does the rest.</p><h2 id="see-also">See Also</h2><ul><li><a href="https://indieweb.org/offline" rel="noreferrer">IndieWeb offline wiki page</a></li><li><a href="https://indieweb.org/offline-first" rel="noreferrer">IndieWeb offline-first wiki page</a></li><li><a href="https://indieweb.org/service_worker" rel="noreferrer">IndieWeb service worker page</a></li></ul><p><strong><em>[</em></strong>1<strong><em>]: </em></strong>If a request is for an image, the cache is checked first, then the network and then finally an “Offline” placeholder image is displayed.</p>
How many hours do you need to work to afford a pint of beer? - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=671142026-03-04T12:34:22.000Z<p>I dropped into a pub in central London and ordered two pints of draught beer. Obviously the price of everything is nuts these days - and doubly so in London - so I only winced a little bit when the cost came to about twelve quid. Shocking, obviously. But as we supped on our pints and discussed the state of the world, I tried to remember how expensive it was to have a pint when I was a <del>lad</del> young man.</p>
<p>I seem to recall that our student pub charged about £2 per pint. And minimum wage around that time was £4 per hour. So a drink was 30 minutes' wages.</p>
<p>Today the minimum wage is about £12 and that pint cost me £6. So, again, about half an hour.</p>
<p>But the human memory is fickle! Let's get some actual historical data.</p>
<p>The UK's Office for National Statistics maintains a dataset of <a href="https://www.ons.gov.uk/economy/inflationandpriceindices/timeseries/czms/mm23">historic draught lager prices</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/01/Draught-lager-per-pint.webp" alt="Graph showing a gentle rise in the cost of draught beer." width="1368" height="573" class="aligncenter size-full wp-image-67116"/>
<p>Well, my memory wasn't <em>too</em> hazy! About £2 when I was at uni. The national average price now is about a fiver - so the London premium wasn't <em>too</em> outrageous.</p>
<p>But how does that compare to wages? The <a href="https://assets.publishing.service.gov.uk/media/5c9e0e72e5274a527faae38a/20_years_of_the_National_Minimum_Wage_-_a_history_of_the_UK_minimum_wage_and_its_effects.pdf">history of the minimum wage</a> is complicated - with several different bands being introduced. It ends up looking something like this:</p>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/01/minwage.webp" alt="Graph showing step changes in wages for different age groups." width="1800" height="600" class="aligncenter size-full wp-image-67115"/>
<p>So I <a href="https://researchbriefings.files.parliament.uk/documents/CBP-7735/CBP-7735.pdf">grabbed the most recent data</a> and plotted the ratio between the cost of draught lager and minimum wage:</p>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/01/ratio.webp" alt="Graph showing ratios of cost of lager vs minimum wage." width="782" height="398" class="aligncenter size-full wp-image-67117"/>
<p>Ah! It turns out that the cost of beer as a ratio to minimum wage is pretty consistent - somewhere between 27 to 40 minutes. Right now, draught lager is <em>cheaper</em> in terms of minimum wage than it has <em>ever</em> been!</p>
<p>Obviously, averages hide all sorts of sins. I'm sure your favourite brand of premium Bohemian pilsner has dramatically risen in price. And minimum wage doesn't necessarily mean disposable income. And you now have a student loan repayment rather than cash being dropped into your account. And the music they play in pubs is crap these days. And you back hurts ever since you tried to match your younger team members pint for pint and slipped in a puddle of your own sick.</p>
<p>Remember, nostalgia is actively dangerous to your mental health.</p>
<blockquote class="bluesky-embed" data-bluesky-uri="at://did:plc:eqh433fdh2bqhvt455e3tg67/app.bsky.feed.post/3m7bh3vii722h" data-bluesky-cid="bafyreif34a63kld5xgjhia2qpcvea3lehqutpll4yqpim554ilfx6noi34"><p lang="en">has anyone else noticed that food tasted better in the past? it was mushy and easy to eat. and the spoon would come at you like an airplane</p>— <a href="https://bsky.app/profile/did:plc:eqh433fdh2bqhvt455e3tg67?ref_src=embed">leon (@leyawn.bsky.social)</a> <a href="https://bsky.app/profile/did:plc:eqh433fdh2bqhvt455e3tg67/post/3m7bh3vii722h?ref_src=embed">2025-12-05T21:38:21.731Z</a></blockquote>
<script async="" src="https://embed.bsky.app/static/embed.js" charset="utf-8"></script>
A soft-landing manual for the second gilded age - Westenberg69a74afc8a9bdf000144e9932026-03-03T21:06:34.000Z<img src="https://www.joanwestenberg.com/content/images/2026/03/ChatGPT-Image-Mar-4--2026--08_03_18-AM.png" alt="A soft-landing manual for the second gilded age"><p>By the summer of 1945, West Berlin had been reduced to rubble. Allied bombing, the Soviet ground assault and Hitler's insistence on Götterdämmerung had destroyed roughly a third of the city's buildings and left most of the rest damaged. There was no functioning government, no reliable electricity, no clean water in large sections of the city, and somewhere around 75 million cubic metres of debris where neighbourhoods used to be. The women who cleared that debris by hand, the Trümmerfrauen, became one of the defining images of the postwar period. Three years later, when the Soviets blockaded the city and tried to starve it into submission, the Western Allies mounted the Berlin Airlift, flying in food and fuel for over a year. And then, against every reasonable prediction, Germany rebuilt. Within a decade, it was the jewel of the Western world, a functioning democracy with a growing economy, universities and civic life, constructed on top of what had been, not long before, a moonscape of broken concrete and ash.</p><p>The conventional wisdom about large-scale disruption assumes that destruction is permanent and that recovery, if it happens at all, will be slow and partial. Berlin is a useful corrective. When the political will existed and the institutional support was there, an entire nation rebuilt itself from almost nothing in a timeframe that would have seemed absurd to anyone standing in the rubble in 1945. The Marshall Plan helped. Allied political commitment helped. But what mattered most was that people decided the situation was not hopeless, and then acted on that decision.</p><p><em>We're going to need that kind of energy.</em></p><p>AI is arriving fast, the old economic arrangements are visibly failing, and the dominant narratives about what comes next have split into 2 equally unhelpful camps: utopian accelerationists who believe the market will sort everything out if we build fast enough, and existential doomers who've convinced themselves that the only possible outcome is either human extinction or permanent mass unemployment. Both camps share a singular trait: they've decided the future is already determined and that human agency is irrelevant to whatever happens next.</p><p>The future is not determined. It never has been.</p><p>I don't entirely believe AI will produce the civilizational wipeout the doomers are predicting. I think there's reasonably good odds the economy will find equilibrium, the way it always does after major technological shifts. New industries will emerge. New forms of work will appear. People will adapt, because people always adapt.</p><p>But equilibrium is not the same as a good outcome. The economy found equilibrium after the Industrial Revolution too, and for several decades that equilibrium included child labour in textile mills and life expectancy in Manchester hovering around 25. What matters is how much unnecessary suffering we allow between here and there, and whether the new normal we settle into is one worth living in.</p><p>What follows is my attempt at a practical roadmap for getting from 2025 to 2035 in a way that makes the landing as soft as possible.</p><p>My bias is toward pragmatism. I believe safety nets work. I believe democracy, despite its many and obvious failings, remains the best system we've got for making collective decisions. I believe that history offers us better guidance than science fiction (or AI influencers on Twitter) for thinking about technological transitions. And I believe somewhat fervently that the people building the most promising models for a post-AI future aren't in Silicon Valley think tanks. They're in rural West Virginia counties, Danish labour offices, and UCL research labs.</p><p>They've already started the work.</p><p>The rest of us need to catch up.</p><h2 id="the-doomers-are-wrong-sorry">The doomers are wrong (sorry)</h2><p>The economic doomer thesis goes like this: AI will automate most cognitive labour within the next decade. This will create permanent mass unemployment on a scale that makes the Industrial Revolution look gentle. The wealth generated by AI will concentrate in the hands of a tiny number of companies and their shareholders. Democracy will be unable to respond because politicians are too slow, too captured, and too ignorant about technology to act in time. The result will be some form of neo-feudalism in which a small AI-owning class controls everything and the rest of humanity becomes economically superfluous.</p><p>Pieces of this deserve to be taken seriously. Wealth concentration is a real and worsening problem, political institutions do lag behind technological change, and the speed of AI development is unprecedented in certain narrow respects. But the overall thesis has a fatal flaw: it treats the current distribution of political and economic power as a fixed constraint rather than a variable. It assumes that because our institutions are currently failing to address inequality, they will inevitably continue failing, forever, no matter what anyone does. That's a deficit of historical imagination on a grand scale.</p><p>Barbara Tuchman, in her magnificent book <em>The March of Folly</em>, documented the recurring pattern of governments pursuing policies that were demonstrably against their own interests, from the Trojan War to the Vietnam War. Her point was not that folly is inevitable. Her point was that folly is a choice, and that at every stage of every disaster she documented, there were people pointing out the obvious alternative, people whose advice was ignored for reasons of ideology, pride, or institutional inertia. The existence of folly doesn't prove the impossibility of wisdom. It proves the necessity of fighting for it.</p><p>The doomers are enacting a version of the error Tuchman catalogued. They've looked at the current state of affairs, noticed that things are going badly, and concluded that "going badly" is the only possible trajectory. But this ignores the entire history of social reform, in which terrible conditions produced political movements that eventually forced institutional change. Child labour was once normal. 60-hour work weeks were once standard. The absence of workplace safety regulations was once considered a natural feature of industrial capitalism. None of these things changed because elites spontaneously became generous. They changed because people organized, fought, and built new institutions that constrained the worst impulses of capital accumulation.</p><p>The AI transition will require the same kind of fight. But it's a fight we can win, and the doomer insistence that we can't is itself one of the obstacles we need to overcome.</p><h2 id="re-graeber-and-bregman">Re: Graeber and Bregman</h2><p>David Graeber, the anthropologist and activist who died in 2020, spent much of his career arguing that our collective imagination about economic possibility had been artificially narrowed. His book <em>Bullshit Jobs</em> made the observation that a startling percentage of the modern workforce was employed in roles that even the people performing them believed to be pointless. Entire categories of employment that existed primarily to maintain bureaucratic structures and power hierarchies rather than to produce anything of genuine value.</p><p>Graeber's insight is directly relevant to the AI conversation because it reframes the automation question entirely. If a large fraction of current employment is already, by the workers' own admission, socially useless, then the automation of those jobs isn't necessarily a catastrophe. It might be a liberation, provided we have systems in place to ensure that the people displaced from pointless work can still eat, pay rent, and maintain their dignity while they figure out what to do next.</p><p>Rutger Bregman picked up a related thread in <em>Utopia for Realists</em>, making the case for universal basic income, open borders, and a 15-hour work week. What made Bregman's argument persuasive wasn't the novelty of any individual proposal (the UBI idea goes back at least to Thomas Paine's <em>Agrarian Justice</em> in 1797) but his insistence on treating these ideas as practical policy rather than utopian dreaming. Bregman marshalled the evidence from actual UBI experiments, from the Manitoba Mincome experiment in the 1970s to GiveDirectly's programmes in Kenya, to argue that giving people unconditional cash transfers tends to produce good outcomes: people don't stop working, they don't drink themselves to death, they invest in their children's education and start small businesses.</p><p>The common thread between Graeber and Bregman is a refusal to accept that the current organisation of work and economic life is natural, inevitable, or optimal. Both argued that we could build something better and that the primary obstacle was not technological or economic but imaginative and political. We've been told so many times that there is no alternative to the current system that we've internalized it as a religious truth, even as the evidence piles up that the current system is making people miserable.</p><p>And here's the part most people miss about markets and entrepreneurship: a guaranteed income floor and universal basic services actually <em>supercharge</em> entrepreneurship. Right now, the single biggest barrier to starting a business in the United States is the risk of losing your health insurance. The single biggest reason talented people stay in jobs they hate is the fear of what happens if they fail. Every UBI study ever conducted has shown an increase in self-employment and business formation among recipients. If you want an economy that actually generates new ideas and new businesses, it turns out the most effective thing you can do is make sure nobody starves if their startup doesn't work out.</p><p>Any serious roadmap for the next decade has to take these insights as a starting premise. The AI transition is going to eliminate and transform millions of jobs, and pretending it won't isn't a strategy. But the outcome of that transformation isn't predetermined. It depends on what we build.</p><h2 id="the-road-not-taken-jeff-atwood-and-guaranteed-minimum-income">The road not taken: Jeff Atwood and guaranteed minimum income</h2><p>In January 2025, Jeff Atwood published <a href="https://blog.codinghorror.com/stay-gold-america/?ref=joanwestenberg.com" rel="noreferrer">"Stay Gold, America,"</a> an essay about the American Dream that turned into something much larger. Atwood co-founded Stack Overflow and Discourse, and he spent 2 decades building internet infrastructure. But "Stay Gold" wasn't about technology. It was about the observation that the United States had entered a period of wealth concentration exceeding the original Gilded Age, with the top 1% of households controlling 32% of all wealth while the bottom 50% held 2.6%. And it was about what that concentration was doing to the foundational promise of equal opportunity.</p><p>I worked with Atwood on the launch and creation of Stay Gold, and what struck me most was how he framed the problem. He wasn't interested in the typical Silicon Valley move of proposing a tech fix for a political failure; he went back to first principles. The American Dream, as James Truslow Adams originally defined it in 1931, was a social order in which everyone could attain the fullest stature of which they were innately capable. Atwood's argument: that this dream had become structurally inaccessible to millions of Americans, and that the act of sharing it, of deliberately extending its reach, was not charity but the fulfilment of the promise itself.</p><p>Atwood and his family pledged half their remaining wealth toward what became the Rural Guaranteed Minimum Income Initiative. Partnering with GiveDirectly and OpenResearch, they began designing rigorous GMI studies in rural American counties where poverty had been entrenched for generations. Mercer County, West Virginia, where Atwood's father was born and the collapse of coal mining left communities hollowed out. Beaufort County, North Carolina, where farming and factory jobs had evaporated. These were places where the American Dream had become, for all practical purposes, a cruel joke.</p><p>The historical lineage of guaranteed minimum income is longer and more distinguished than most people realize. Paine proposed a retirement pension funded by estate taxes in 1797. Social Security, established in 1935, cut senior poverty from roughly 50% to 10%. Martin Luther King Jr. made the moral case for direct cash disbursements in <em>Where Do We Go From Here: Chaos or Community?</em> in 1967, arguing that a guaranteed income was the simplest and most effective weapon against poverty. The Earned Income Tax Credit, established in 1975, became the 2nd most effective anti-poverty tool in America after Social Security. And in 2019, Mayor Michael Tubbs launched the Stockton Economic Empowerment Demonstration, providing 125 residents with $500 per month in unconditional payments for 2 years. The results showed improved financial stability, increased full-time employment, and better mental health outcomes.</p><p>Atwood's contribution was to connect this lineage to the specific crisis of the present moment: the simultaneous arrival of extreme wealth concentration and AI-driven economic transformation. His speech at Cooper Union's Great Hall in March 2025, where he appeared alongside Alexander Vindman, laid out the case with characteristic directness. If the wealth exists (and it does), and if the evidence shows that guaranteed income works (and it does), and if the alternative is watching millions of people get trapped in poverty while their economic foundations crumble beneath them (and it is), then the failure to act is a political choice, not an economic inevitability.</p><p>The OpenResearch study, completed in 2023, was the largest and most detailed GMI study ever conducted in the United States. Its findings reinforced what every previous study had shown: people who received unconditional cash didn't blow it on luxuries. They shared it with others. They went out of their way to help others in desperate need. They started small businesses. They invested in their kids. What guaranteed income did went beyond individual financial stability. The real effect was the network of economic security spreading through communities, strengthening the bonds between people that poverty systematically destroys.</p><p>When AI displaces workers at scale, the critical variable is whether those workers have a floor beneath them or whether they fall into a void. A guaranteed income provides the floor. It preserves the community ties and social networks that people need to rebuild their economic lives. And the evidence, accumulated across decades and dozens of studies, consistently shows that it works.</p><p>Guaranteed minimum income really is the road not taken in American (and global) economic policy, the path that was available at every stage and was always rejected in favour of means-tested bureaucracy and moral panic about dependency. The AI transition gives us a reason, and perhaps the last best chance, to finally take it.</p><h2 id="what-else-we-need-to-build">What else we need to build</h2><p>Guaranteed minimum income is the foundation, but it's not the whole structure. There are 4 other critical investments that need to happen between now and 2035.</p><p><strong>Universal basic services as durable infrastructure.</strong> The UCL Institute for Global Prosperity has championed the idea of guaranteeing every citizen access to basic services regardless of employment status: healthcare, housing, education, transportation, communications, food security. Most developed nations already provide some of these universally. The expansion would mean filling in the gaps and making the guarantee explicit. Why services alongside income? Because services are harder to claw back politically. Once a country has a national health service, eliminating it becomes almost impossible, as every British politician who has flirted with privatising the NHS has discovered. Cash transfers are vulnerable to the endless cycle of means-testing and moral panic. Universal services create durable infrastructure that survives changes in government.</p><p><strong>Portable benefits and the end of employer-dependent welfare.</strong> The system in which your health insurance, retirement savings, and professional identity are all tied to your employer made sense in the era of lifelong employment at a single company. That era ended decades ago. The AI transition will accelerate job turnover dramatically, and the employer-dependent welfare model will become actively dangerous, trapping people in declining industries because they can't afford to lose their benefits. It also kills entrepreneurship stone dead: you don't quit your job to build something new if quitting means your family loses health coverage. Denmark's "flexicurity" model combines flexible labour markets with generous unemployment insurance and active retraining programmes, producing low long-term unemployment despite high job turnover. These models work, and the evidence base is extensive. Denmark, incidentally, has one of the highest rates of entrepreneurship in Europe.</p><p><strong>A public AI infrastructure layer.</strong> Right now, the most powerful AI systems are controlled by a handful of private companies spending tens of billions on compute infrastructure. If this trajectory continues, we'll end up with an AI oligopoly controlling the core cognitive infrastructure of the 21st century economy. We've already run this experiment with social media platforms and the results have been mixed at best. The alternative is government-funded compute clusters, open-source foundation models, and public research institutions that provide AI capabilities as a utility. The model is the public research university, the original ARPANET, the BBC: fund a public institution with a clear mandate to serve the public interest and let it provide a baseline that the private sector has to compete with.</p><p><strong>Democratic governance of algorithmic systems.</strong> AI systems are already making consequential decisions about who gets a loan, who gets hired, who gets paroled, what news you see. These decisions are largely invisible, poorly documented, unaccountable, and unappealable. This is a governance failure, and fixing it doesn't require any technological breakthrough. We know how to create accountability structures for decision-making systems because we've been doing it for centuries. The EU's AI Act provides a template. Citizens' assemblies on AI policy, modelled on the Irish Citizens' Assembly that broke the political deadlock on abortion, would give ordinary people meaningful input into the design and deployment of systems that affect their lives.</p><h2 id="obstacles-etc">Obstacles etc</h2><p>The first obstacle is political. Everything I've described requires massive public investment, which means either raising taxes on the wealthy and on corporations or redirecting existing spending. The wealthy have enormous political influence in every democracy, and they will resist any attempt to fund a more generous social contract at their expense. This has been the central political conflict of every democratic society since Athens. It gets worse when inequality is high, because extreme wealth translates directly into extreme political power.</p><p>The second obstacle is ideological. 40 years of individualist economics have embedded the assumption that markets are always more efficient than governments, that public provision of services is inherently wasteful, and that individual responsibility should take precedence over collective insurance. These assumptions are deeply held by politicians, economists, media commentators, and voters, and they won't be dislodged by a single white paper or a clever policy proposal. Changing the ideological terrain requires sustained intellectual and political work over years.</p><p>The third obstacle is coordination. Many of these proposals work best when implemented at scale, ideally internationally. A single country that raises corporate taxes to fund universal basic services while its neighbours maintain lower rates will face capital flight. International coordination is possible (the OECD's minimum corporate tax agreement shows this) but difficult and slow.</p><p>The fourth obstacle is the tech industry itself. The major AI companies have strong incentives to resist public AI infrastructure, algorithmic accountability, and any regulation that might slow their growth. They'll lobby, fund think tanks, produce studies showing regulation will destroy innovation, and warn about China winning the AI race. This playbook is familiar from every previous round of tech regulation debates, and it has been effective.</p><p>The fifth obstacle is us. Our cynicism, our exhaustion, our tendency to scroll past the policy debate and doom-post about the inevitable robot apocalypse. Doomerism is a form of political paralysis. If you believe the future is already determined, you don't organize, you don't vote, you don't fight. You wait for the catastrophe and feel validated when it arrives.</p><h2 id="how-we-beat-the-doom">How we beat the doom</h2><p>Overcoming these obstacles is the actual work of the next decade. And it starts with a recognition that none of them are unprecedented.</p><p>The political obstacle of concentrated wealth was faced and partially overcome during the Progressive Era in the United States and the postwar social democratic settlement in Europe. The ideological obstacle of market fundamentalism was challenged and partially overturned by the Keynesian revolution of the 1930s and '40s. The coordination obstacle of international cooperation was addressed, however imperfectly, by the postwar institutional order: the United Nations, the Bretton Woods system, the European Coal and Steel Community that grew into the EU. The obstacle of industry resistance has been overcome repeatedly, from railway safety to pharmaceutical regulation to environmental protection. And the obstacle of public cynicism has been overcome every time a social movement successfully mobilized people around a vision of a better future.</p><p>The playbook is there. It's in the history books and the policy research. It's in the lived experience of countries that have already built more humane economic systems than the Anglo-American default. You can see it in places like Mercer County and Beaufort County, where the GMI studies are already gathering data on what happens when you actually give people a floor to stand on.</p><p>Political will isn't a resource that exists in fixed supply. It's something that gets created through argument, organizing, coalition-building, and the slow, grinding work of changing what people believe is possible. Bregman was right about this: the Overton window isn't a natural phenomenon. It's a political construction, and it can be moved.</p><h2 id="a-10-year-calendar">A 10-year calendar</h2><p><strong>2025-2027: Foundation.</strong> Pass legislation requiring algorithmic transparency and accountability for high-risk AI systems. Establish public AI research institutes with serious funding. Scale the Atwood-GiveDirectly rural GMI model to additional counties, building the evidence base. Begin the political conversation about universal basic services by proposing pilot programmes in sympathetic jurisdictions.</p><p><strong>2027-2029: Construction.</strong> Implement universal basic services pilots. Roll out portable benefits in at least one major economy. Scale up public AI infrastructure to provide competitive open-source alternatives to private models. Expand rural GMI from individual counties to regional programmes, using accumulated data to refine the model. Begin international negotiations on AI governance standards.</p><p><strong>2029-2031: Expansion.</strong> Expand universal basic services from pilots to national programmes. Introduce guaranteed minimum income legislation building on 5 years of study data. Massively increase public investment in human-centred services: healthcare, education, elder care, community infrastructure.</p><p><strong>2031-2033: Integration.</strong> Link the components into a coherent system. Ensure that the social safety net, portable benefits, GMI, and AI governance framework work together to provide real security during economic transitions. Shift from unemployment insurance to transition insurance, recognizing that job changes will be frequent and that people need support during transitions as much as during unemployment.</p><p><strong>2033-2035: Consolidation.</strong> Lock in the gains. Make the new institutions as politically durable as possible by building broad public support and embedding them in legal frameworks that are difficult to reverse. Evaluate what's working and adjust what isn't.</p><p>This is an aggressive timeline. It assumes a level of political ambition and institutional capacity that may be optimistic. But it's not fantasy. The postwar welfare state was built in roughly this timeframe. The New Deal transformed American government in under a decade. West Berlin went from 75 million cubic metres of rubble to a prosperous, functioning city in less than 15 years. When the political will exists and the institutional support is there, the speed of transformation can be shocking.</p><h2 id="staying-gold-in-the-age-of-ai">Staying gold in the age of AI</h2><p>There's a passage in S.E. Hinton's <em>The Outsiders</em> where Johnny Cade tells Ponyboy Curtis to "stay gold," referencing Robert Frost's poem "Nothing Gold Can Stay." The poem is about the inevitability of loss, about how the first green of spring is also its most beautiful and most fragile. It's a melancholy poem, and in context a melancholy injunction: stay good, stay kind, stay open to beauty, even though the world will do its best to harden you.</p><p>Atwood's use of "stay gold" carried that bittersweet quality but pushed it further. His argument was that the American Dream isn't an individual achievement. It's incomplete until it's shared. The act of sharing, of deliberately extending economic security and opportunity to people who've been locked out, is what makes the dream real. This is backed by the data from every GMI study ever conducted: when you give people economic security, they share it. They invest in their families and their neighbours. The network effect of opportunity turns out to be vastly more powerful than the individual effect.</p><p>Apply this to the AI transition and the implications are hard to overstate. If you build the institutions that share the gains, if you create guaranteed income floors and universal services and portable benefits and democratic governance, then AI becomes a tool for broadly shared prosperity rather than a mechanism for further concentration. It becomes the platform on which a million new businesses get built, because people have the security to take the risk. The technology doesn't determine the outcome. The institutions do.</p><p>The accelerationists believe that technological progress will automatically produce good outcomes and that any attempt to steer or constrain it is futile. The doomers believe that bad outcomes are inevitable and that any attempt to prevent them is naive. The uncomfortable middle ground is where the real work happens: the future will be determined by human choices, and those choices will be difficult and contested, but they are ours to make.</p><h2 id="the-case-for-stubborn-optimism">The case for stubborn optimism</h2><p>I want to end with something that might sound naive, and I'm okay with that.</p><p>The case for optimism about the AI transition is not that everything will be fine. Everything will not be fine automatically. I believe we'll find equilibrium regardless. The economy is adaptive, and people are resourceful, and new forms of work will emerge in ways none of us can predict. The case for optimism is that we don't have to settle for whatever equilibrium the market produces on its own.</p><p>We have, at this specific moment in history, an unusual combination of factors that makes it possible to actively shape the landing. The economic resources to fund a generous social contract exist. The historical evidence that safety nets and public institutions work is extensive and consistent. We know how to build AI governance systems that are actually enforceable. Public awareness that the current trajectory is unsustainable is growing. And people like Atwood are already doing the work, already running the studies, already building the evidence base for guaranteed minimum income in the communities that need it most.</p><p>What we lack is the political organization to translate awareness into action, and the imaginative confidence to believe that alternatives are possible. These are real deficits. But they're deficits that have been overcome before, in circumstances far more dire than our own.</p><p>The Trümmerfrauen who cleared Berlin's rubble by hand didn't have a 10-year plan. They had buckets and wheelbarrows and the determination to rebuild what had been destroyed. The Marshall Plan gave them institutional support, and the political commitment of the Western Allies gave them security, but the basic act was human: people deciding that the rubble was not the end of the story.</p><p>The doomers want you to believe that the game is already over. The accelerationists want you to believe that you don't need to play. Both positions are comforting in their way, because both relieve you of the burden of actually doing something.</p><p>A serious 10-year roadmap offers no such comfort. </p><p>The future is undetermined, the stakes are enormous, and the work is ours to do.</p><p>That's the most optimistic thing I can imagine.</p><p>The future is still up for grabs.</p><p>So grab it.</p>22.00.0186 I uploaded your email address to GitHub - Johnny.Decimalhttps://johnnydecimal.com/22.00.0186/2026-03-03T18:18:13.000Z<h1 id="i-uploaded-your-email-address-to-github">I uploaded your email address to GitHub</h1>
<p>Further to my discovery of <a href="https://johnnydecimal.com/22.00.0185/">the data leak</a> earlier today, I spent most of the day trying to figure out what had happened. Finally, on a walk with Lucy after we knocked off, the lightbulb went off.</p>
<p>I didn't, did I? Surely not.</p>
<p>I did.</p>
<p>I uploaded a .csv containing your email address to a public GitHub repository. (For the non-technical of you: that's just a web page. I published your email address on a web page.)</p>
<p>Good news: not a 'hack' in the traditional sense. Just a dumb mistake.</p>
<p>Bad news: <em>oof</em>. Johnny. So bad.</p>
<p>To you, whose address is now public, I can only offer my humblest and sincerest apology. Unless you know me personally you won't know what this means to me.</p>
<h3 id="full-report-to-follow">Full report to follow</h3>
<p>I'll write this up in detail tomorrow. There's a <em>lot</em> to learn.</p>
<p>I haven't mailed everyone affected yet because there hasn't been much to say. I'll send a link to tomorrow's post once it's up.</p>
<hr>
<p><em>100% human. 0% AI. Always.</em></p>The Church at Varengeville by Monet - James' Coffee Bloghttps://jamesg.blog/2026/03/03/the-church-at-varengeville-by-monet/2026-03-03T15:13:49.000Z
<p><em>I am writing about a few paintings to help me build my description skills. My analyses are not formal or comprehensive. If nothing else, I hope that you enjoy the painting that I feature!</em></p><p>The warm colours in Monet’s <a href="https://barber.org.uk/claude-monet-1840-1926/"><em>The Church at Varengeville</em></a> (1882) stood out to me the moment I saw them in a corner of the Courtauld Institute in London [1].</p><img alt="The Church at Varengeville" class="kg-image" loading="lazy" src="https://barber.org.uk/wp-content/uploads/2012/09/monet-1024x821.jpg"/><p>In the top left of the painting, the subject, the church of Varengeville, is painted. But the church takes up a relatively small portion of the painting: a much greater portion is dedicated to the cliffside, bushes, and two trees that span from the bottom to the top third of the canvas. This is in contrast to other paintings of churches that Monet has made like the Roen Cathedral and the Church at Vétheuil where the church takes up much more of the canvas.</p><p>The Church of Varengeville stood out to me for its use of colour; Monet paintings always make me feel something, and one question I would like to answer in my studies is why his use of colour makes me feel the way it does. The sky is a warm yellow. Is the sun about to set?</p><p>I appreciate the contrast between the sky and the ocean: the sky is yellow and bright, whereas the ocean is a soft blue with yellow tones. The sea and sky are separated by a horizon line.</p><p>The bushes in the foreground are more clearly defined than the fields of grass; the bushes use a mix of vivid yellows and reds and oranges, whereas the grass uses a more limited range of colours. The left side of the painting is orange. I am unsure what phenomena or flora it depicts.</p><p>I was mesmerised while looking at this painting, studying up close the detail of the brushstrokes in the bushes and from afar the overall composition and use of colour. I like to look at paintings from many different angles to help me understand what I see, and if what I see is different as I change my distance from the work.</p><p>Now that I am back home and analysing the painting, I realise that, if I put a romantic lens on, the two trees in the foreground take on new significance for me. There is something beautiful about there being two trees so close seeing the sun set together. </p><p>Visual analysis aside: this painting brings me joy.</p><p><strong><em>[</em></strong>1<strong><em>]: </em></strong>The painting is displayed as part of a temporary exhibit while the Barber Institute of Arts that usually houses the painting is renovated.</p>
What Interested me Today 6 - Joel's Log Fileshttps://joelchrono.xyz/blog/what-interested-me-today-62026-03-03T14:40:00.000Z<p>I already share links every time I do week notes, but I still read quite a bit of things on my FreshRSS instance and thought I’d share some more thoughts on articles and things I found interesting today—maybe yesterday.</p>
<p>Just some musings here for you guys to enjoy, check out the original posts as well, of course.</p>
<h2 id="from-1password-to-apple-passwords"><a href="https://pawelgrzybek.com/from-1password-to-apple-passwords/">From 1Password to Apple Passwords</a></h2>
<p>I find amusing how Apple has managed to win over so many tech enthusiasts over the years, such a curious phenomena, to have many people embracing its services despite all the caveats they have.</p>
<p>Of course, practicality is not to be dismissed, but I’m still baffled.</p>
<p>No single company actually cares that much about you, and the moment they see the opportunity, your data can be a bargain chip to keep you locked down, which is okay sometimes, until it isn’t anymore.</p>
<p>Think about how Google initially promised infinite storage for Google Photos and now it’s only 15GB shared with Google Drive unless you pay a subscription fee. Or about Apple itself making their current operating system inaccessible and impossible to understand to plenty of people who just don’t get their new glassy UI design.</p>
<p>In any case though, I guess that KeepassXC which I use today <em>could</em> do an oopsie too, and potentially lead to data loss of my password database…</p>
<p>So, yeah, backups are what matters, and I’m glad they’re being done here.</p>
<h2 id="steam-next-fest---february-2026"><a href="https://gametrends.pika.page/posts/steam-next-fest-february-2026">Steam Next Fest - February 2026</a></h2>
<p>I wanted to write a similar post to this one myself, but I don’t think I am enough of a PC gamer for it—I also got extremely lazy. This event from Steam is quite insane, with lots of demos available to try out.</p>
<p>And what did I do instead? Play <em>Peak</em>, and watch videos about what demos are worth trying, without actually giving them a go.</p>
<p>Oh I’m also very happy that <em>Alabaster Dawn</em> shows up in here, that game looks like a masterpiece already and I’m dying to give it a go one day, it’s from the same people who made <em>CrossCode</em> so, it ought to be great.</p>
<p><em>Vampire Crawlers</em> looks like absolute danger too, I am extremely thankful that it’s not available on mobile phones yet, because it really seems like the only thing that could rival <em>Slice & Dice</em> for me…</p>
<h2 id="liar-liar-time-on-fire"><a href="https://aleemshaun.com/posts/liar-liar-time-on-fire">Liar, Liar Time on Fire</a></h2>
<p>This is a post from a new blog I just started to follow and I already find it very very relatable. Aleem looks at screen usage, sees it is too high, and well, now he’s very worried about it and shall do a lot of things to try and fight back.</p>
<p>I am not one of those people that can say “I use my phone for a lot of productive things”, I kinda just read Manga, play Sliced & Dice, chat on Signal or Discord, and scroll Reddit or the Fediverse, maybe Podcasts too (AntennaPod for the win).</p>
<p>My screen time today as I write this is 6 hours, but I could easily reach 9 or 10 hours in days where I don’t read or write as much as I’ve done this time.</p>
<p>I vibe with this quote:</p>
<blockquote>
<p>I want to make more deliberate choices about how I use my time. That seems much smarter than the phone claims to be. And perhaps in the silence the phone was trying to drown out, I’ll discover more human opportunities for wonder and joy.</p>
</blockquote>
<h2 id="ipod-vs-smartphone---which-lasts-longer"><a href="http://82mhz.net/posts/2026/03/ipod-vs-smartphone-which-lasts-longer/">iPod vs Smartphone - which lasts longer?</a></h2>
<p>Andreas is back with some very whacky tech shenanigans. He replaced the battery of his iPod and decided it would be a fun idea to compare how it would fare against a modern smartphone.</p>
<p>I seriously can’t understand how is it that he thoughts a 650 mAh battery would be able to beat a modern smartphone with about 4000 mAh.</p>
<p>Like, this was clearly going to go one way as soon as Airplane Mode got enabled…</p>
<p>But hey, the experiment was really fun to read and I enjoyed the journey even if the destination would be clear as day.</p>
<p>I can only wonder why not do some sort of battery mod for the iPod while being at it? If the PSP can have battery mods I’m sure the iPod community has done plenty as well. It would be fun to try I think.</p>
<p>(The related <a href="https://mastodon.bsd.cafe/@82mhz/116136048173470023">Mastodon thread</a> is very fun, btw)</p>
<h2 id="a-ham-radio-t-shirt-design-contest"><a href="https://hamvillage.org/org/shirt-design-contest">A Ham Radio T-Shirt Design Contest</a></h2>
<p>I have zero idea about ham radio, I know nothing about it. But the idea of designing a T-Shirt and the theme of the contest itself is actually very very interesting to me, the prompt is: “Signal from the Static.”</p>
<p>Father ominous, I must say.</p>
<p>I’m kinda inspired to try my hand at something, using Inkscape and messing around for a bit…</p>
<p>We’ll see how it goes! And hey, maybe some of you want to participate too?</p>
<h2 id="final-thoughts">Final thoughts</h2>
<p>Here I am being grumpy about Apple devices taking over tech enthusiasts while at the same time I read and share two articles talking about Apple products, bleh.</p>
<p>This was fun! I just get to banter and talk whatever I want and maybe some of it clicks with you and maybe some of it is rather useless, but I was feeling like making a random stream of thoughts kind of post, and here it is! Enjoy.</p>
<p>This is day 26 of <a href="https://100daystooffload.com">#100DaysToOffllad</a></p>
<p>
<a href="mailto:me@joelchrono.xyz?subject=What Interested me Today 6">Reply to this post via email</a> |
<a href="https://fosstodon.org/@joel/116165865493163496">Reply on Fediverse</a>
</p>Can we build the dog? - Werd I/O69a6e5915760dd00017d27272026-03-03T13:46:24.000Z<img src="https://images.unsplash.com/photo-1607948471566-efd3bf038a67?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDE2fHxyb2JvdCUyMGRvZ3xlbnwwfHx8fDE3NzI1NDU1MTl8MA&ixlib=rb-4.1.0&q=80&w=2000" alt="Can we build the dog?"><p>“Will the dog hunt?”</p><p>My sneakers squeaked on the concrete floor. Twenty entrepreneurs in black hoodies looked up at me, taking notes. This room had been a working garage once; now, we <a href="https://matter.vc/meet-matter-seven/?ref=werd.io">ceremonially opened the garage door to let in new cohorts of early-stage media startups</a> with the potential to <a href="https://medium.com/matter-driven-narrative/defining-change-media-for-good-2fdb07b3725b?ref=werd.io">change media for good</a>. Outside, the San Francisco traffic honked and screeched.</p><p>We were midway through the bootcamp: the week-long course at the beginning of the accelerator that aimed to teach startups the fundamentals of human-centered venture design. We’d taken them out of their comfort zone to help them use journalistic skills to understand who they were building for and why. We’d helped them to think about how to effectively tell the story of their business in a way that helped them sharpen their underlying strategy.</p><p>And now I was trying to explain <em>feasibility</em>.</p><p>I echoed <a href="https://point.co/?ref=werd.io">Corey Ford</a>, the Managing Director, who had laid out the groundwork in the days before. Repetition was our friend.</p><p><em>Desirability</em>, I explained, is your user risk: are you building something that meets a real person’s needs? Will the dog hunt?</p><p><em>Viability</em>, in turn, is your business risk: if you are successful, can your venture succeed as a profitable, growing business? We stretched the metaphor a little bit here: will the dog eat the dog food?</p><p>And now it was time to explore <em>Feasibility</em>: can you provide this service with the team, time, and resources reasonably at your disposal? I leaned in conspiratorially and vamped: <em>can we build the dog?</em></p><p>It was the best job I ever had: using my experience as a founder, an engineer, and a storyteller to support teams that were genuinely trying to make a difference. People who went through Matter have gone on to help countless newsrooms succeed by being more empathetic and product-minded; some have left media and even gone on to build hospitals.</p><p>I went through Matter as the founder of Known in 2014 and came back to support other founders a few years later. Since then, how I think about feasibility has completely changed.</p><h3 id="the-build-vs-the-long-wagging-tail">The build vs the long, wagging tail</h3><p>The center of gravity for feasibility, at least in my mind, used to be the build stage. How do you build the initial version of a tool or a service that provides <a href="https://benwerd.medium.com/founding-a-startup-just-one-more-time-37f7a4b9b22e?ref=werd.io">a minimum desirable experience</a> to meet your user’s need?</p><p>Startups also need to consider how to make it scale so that you can address a larger potential number of users with the time, team, and resources <em>potentially</em> at your disposal. If you can’t get there with the resources you have, could you get there with investment dollars you could realistically raise?</p><p>In a newsroom or other organization the formula is a little bit different. You’re probably not raising money for a specific tool or a service — although, sometimes, grant funding or funding from a corporate parent <em>is</em> available for certain things. But you’re most often asking whether you can provide the service or tool with the time, team, and resources <em>currently</em> at your disposal. Often, your time is limited, your team is small, and your resources are meagre. You have to make stark tradeoffs.</p><p>In both contexts, you don’t want to waste time spinning your wheels building solutions to problems other people have already solved. <a href="https://werd.io/build-what-makes-you-special-buy-the-rest/">I’ve already written about building vs buying for newsrooms</a>:</p><blockquote>Newsroom tech teams are like startups in that they’re running with limited resources and constantly trying to assess how they can provide the most value. Back when I was Director of Investments at Matter Ventures, I advised them to spend their time building the things that made them special — their differentiating value — and using the most boring, accepted solution for everything else.<br><br>It's a rule of thumb that works universally: build what makes you special and buy the rest. But the critical difference is that, in newsrooms, what makes you special is the journalism that software enables, not the software itself.</blockquote><p>The cost of building something new has fallen through the floor over the last decade. Developer tools have become more powerful, numerous, and freely available. Open source has exploded with libraries that can help you get to an initial version much faster.</p><p>Enter AI. Almost without warning, <a href="https://werd.io/good-vibes-bad-vendors/">AI-enabled tools dramatically expanded what a resource-strapped team can create</a>. It’s a genuine sea change. The more founders and senior engineers I speak to who are actively using these tools, the more stories I hear about accelerated development. People are building smaller tools that would have taken many sprints in less than a day; founders are building entire startups that might have taken six months in less than one.</p><p>But all code needs to be maintained. There are bugs, libraries need to be upgraded, underlying platform changes introduce security flaws and incompatibilities. Changes in business needs mean that tools and services need to be adjusted. All of those things add up to a maintenance overhead that comes with introducing any new tool or service. If we rapidly build more and more software, that maintenance overhead accumulates at speed. Even if we have the discipline to keep our technical footprint small, we’re not absolved from doing what has to be done to keep everything running.</p><p>When we consider feasibility, the center of gravity is no longer in building the thing. It’s <em>supporting</em> it.</p><h3 id="a-shared-rubric-reduces-risk">A shared rubric reduces risk</h3><p>The dynamics may have changed but every team still needs to make a bet about whether we can build and support a project before it takes it on. If something is obviously not feasible, the team shouldn’t do it. On the other hand, if a team doesn’t have a clear, shared understanding of how to assess feasibility, it can become an easy way for someone to subjectively shut down a project for arbitrary reasons. Without a clearly shared understanding of risk, the <em>idea</em> of risk can be poison.</p><p>So that’s what we need: a shared rubric for assessing the feasibility of a project. Our assessments won’t always be right, and we always learn new things about a project in the course of building or supporting it. But while complete certainty is hard to achieve, this will at least provide <em>directional</em> information about whether we can do it.</p><p>There are existing frameworks, but they’re mostly designed for large enterprise environments: instead of giving you a directional gut check, they produce documents used in commissioning vendors, justifying budgets to executives, and satisfying governance processes. <a href="https://business.tutsplus.com/articles/can-we-really-do-it-how-to-conduct-a-telos-feasibility-study--cms-21442?ref=werd.io">TELOS</a> — Technical, Economic, Legal, Operational, and Scheduling — feasibility tests are very broad and don’t consider technology alone. <a href="https://www.topdevelopers.co/blog/feasibility-study-in-software-development/?ref=werd.io">PIECES</a> examines whether a proposed project will improve the status quo across Performance, Information, Economics, Control, Efficiency, and Services. Both are useful to understand, but also not quite what most time-strapped contexts demand. We need something scrappier.</p><h3 id="a-prototype-rubric-for-feasibility">A prototype rubric for feasibility</h3><p>Here are some questions a team can ask themselves. Not only are they useful in themselves, but you can use them for alignment: if a product manager ranks a factor with a low score but a senior engineer on the team ranks it with a high one, you know there’s a problem that you need to dig into.</p><p>Each of these questions can lead to its own targeted discussion. The purpose of the rubric is not to be a thought-ending exercise: it’s to align a team around what’s actually important to consider, and open up conversations about any disagreements so that everyone can come to a consensus.</p><p>Each person on the team should run through the rubric — perhaps asynchronously — and then share their results with the group in a shared meeting.</p><p>These questions take our AI engineering context into account: questions about exploring new architectures are weighted lower than they would have been ten years ago.</p><h4 id="1-the-problem-context-25-points">1. The problem context (25 points)</h4><p><strong>How much of this project's scope is a black box? (10 points)</strong><br><em>1 = We have built this exact thing before. 10 = This is completely new territory; we don't even know what questions to ask yet.</em></p><p><strong>How much friction will our existing tech stack, legacy systems, or organizational quirks add to the build? (10 points)</strong><br><em>1 = Greenfield project using our preferred stack; 10 = Navigating a maze of legacy spaghetti code or systems.</em></p><p><strong>How fundamentally difficult is the core problem we are trying to solve? (5 points)</strong><br><em>1 = A standard CRUD app; 5 = Uncharted algorithmic research.</em></p><h4 id="2-execution-15-points">2. Execution (15 points)</h4><p>Here, the “development period” is tailored to your unit of project organization time on your product roadmap. On some teams, it’s a quarter; for others, it’s half a year. These questions are <em>not</em> meant to be considered at the sprint level.</p><p><strong>How much of the team’s total capacity will the initial build consume? (10 points)</strong><br><em>1 = We can spin this up in an afternoon; 10 = Consumes 100% of the engineering team's capacity for the development period.</em></p><p><strong>How well do the skills required match the people we currently have? (5 points)</strong><br><em>1 = We have deep expertise here; 5 = Requires learning new frameworks from scratch.</em></p><h4 id="3-the-long-wagging-tail-60-points">3. The long, wagging tail (60 points)</h4><p>While most of these questions consider up-front issues, this section describes the <em>ongoing</em> overhead for a team. This represents risk: time a team spends working on maintaining an existing tool is time it can’t spend building anything new or maintaining other tools. Over time, without careful lifecycle management and brutal decision-making, a team’s bandwidth can disappear into ongoing maintenance.</p><p><strong>How long are we committing to keep this system alive? (20 points)</strong><br><em>1 = A disposable prototype or short-term event tool (weeks or months); 20 = A permanent, foundational system we expect to rely on for years.</em></p><p><strong>How much of our team’s capacity will keeping this system alive consume in a typical month? (30 points)</strong><br><em>1 = Set it and forget it; 30 = Requires daily babysitting, constant bug fixes, and continuous adaptation to upstream changes.</em></p><p><strong>How heavily does this project rely on teams, platforms, APIs, or vendors that we do not control? (10 points)</strong><br><em>1 = Fully self-contained; 10 = Dependent on unstable APIs, beta AI models, or restrictive third-party vendors.</em></p><h4 id="4-the-blast-radius-40-points">4. The blast radius (40 points)</h4><p>Because modern tools let small teams build powerful things quickly, the risk of deploying something dangerous or irreversible is higher. This category is weighted heavily to catch those risks.</p><p><strong>How sensitive is the information that this tool handles? (20 points)</strong><br><em>1 = Public, anonymous data; 20 = Handling highly sensitive PII, whistleblower documents, or financial data.</em></p><p><strong>How catastrophic is it if we ship an imperfect, glitchy version? (10 points)</strong><br><em>1 = We can ship it broken and iterate safely; 10 = Mission-critical; if it’s not perfect on day one, we burn trust or face legal ruin.</em></p><p><strong>If we realize this was a mistake halfway through, how hard is it to undo? (10 points)</strong><br><em>1 = A two-way door; we can easily turn it off; 10 = A one-way door; involves irreversible data migrations or permanent structural changes.</em></p><p>Once everyone has tallied their numbers, compare your total scores out of 140. This is nothing more than a temperature check: again, it should be considered a conversation-starter, not the final word.</p><p>Roughly, here’s how the scores break down:</p><p><strong>0–45: Green light.</strong> This project is highly feasible. The initial lift is manageable, the ongoing tax on your team is low, and the blast radius if things go wrong is minimal. Build the dog.</p><p><strong>46–95: Yellow light.</strong> This is the danger zone of hidden costs. You can probably build this, but the lifespan, ongoing maintenance, vendor dependencies, or security requirements will create a permanent drag on your team’s velocity. Before proceeding, ask yourselves: what existing project are we willing to sunset to make room for this new maintenance burden? What’s the opportunity cost, and is the lift to the organization worth it? While this rubric only considers feasibility, this is a good time to go back to desirability and make sure the juice is worth the squeeze.</p><p><strong>96–140: Red light.</strong> This project is fundamentally infeasible with your current resources. The complexity is too high, the blast radius is too dangerous, or the multi-year maintenance load will simply sink your engineering team. If this project is absolutely vital to the business, you cannot build it scrappily: you need to buy an enterprise solution, hire specialists, or radically reduce the scope by choosing a much smaller problem to solve first.</p><p>Once again, this isn’t the be-all and end-all. For one thing, the rubric is not a simple average: pattern matters as much as the total. It’s worth checking for category dominance: if your scores are generally low but are much higher for the long, wagging tail, that doesn’t mean you have an unambiguous green light. These categories may also surface other conversations that aren’t cleanly captured by the rubric. But the first step towards shared understanding is building a structure to achieve understanding <em>about</em> — and hopefully this gets you some of the way there.</p><p>And please: talk to people. For more complicated projects, I always think it’s a good idea to speak to experts in order to validate your assumptions about feasibility. For <em>any</em> project, speaking to your users to make sure you’ve nailed desirability, and speaking to equivalent businesses to validate your viability assumptions, are crucial. The map is not the territory, and sometimes you need multiple maps.</p><h3 id="can-we-build-the-dog">Can we build the dog?</h3><p>The beauty of a shared rubric isn’t that it automatically makes decisions for you. It’s that it forces a team to look at the exact same map. If a product manager scores the project a 40, but a senior engineer scores it a 105, you’ve found an area of disagreement that you need to explore. It’s far better to do that early, before you dive into complicated specification work or writing code.</p><p>In a world where AI and modern tooling make it dangerously easy to spin up new software, our ultimate constraint is no longer our ability to type code. It’s our capacity to care for the things we bring into the world. Saying "no" to a project with a massive, hidden maintenance burden isn't a failure of imagination; it is how you protect your team’s time so they can focus on the journalism, the community, or the core mission that actually makes your organization special.</p><p>Today, building the dog is the easy part. The real question is whether you have the time, energy, and resources to feed it, walk it, and take it to the vet for the next five years.</p><p>If you do, then by all means: let’s see if it hunts.</p>State of the Browser 2026 - James' Coffee Bloghttps://jamesg.blog/2026/03/03/state-of-the-browser-2026/2026-03-03T12:49:41.000Z
<p><em>State of the Browser was electric.</em> This is how I summarised my experience at the annual <a href="https://2026.stateofthebrowser.com" rel="noreferrer">State of the Browser</a> event in London in my notes. I like to capture moments as they happen, then write about them later. The note is the essence of a blog post; the starting point. The note blossoms at home.</p><p>State of the Browser is a conference about the web. There is always a nice mix between web technologies, standards, and designing for the web. This year was no different. The day started by learning about CSS anchor positioning and ended with a demo of an interactive video game on the web, between which everything from accessibility compliance to introversion as covered.</p><p>What makes State of the Browser distinct is that the talks generally peel back layers of the web, allowing the audience an insight into a part of the web they may not see. This was exemplified by Jason Williams’ talk “<a href="https://2026.stateofthebrowser.com/speaker/jason-williams/" rel="noreferrer">Temporal: It’s about time</a>”, which was all about how the Temporal API standard was developed. If I heard correctly, work on the standard – which provides a more reliable, intuitive way to work with dates and times in the browser – has taken around ten years. There are four thousand tests that accompany the standard.</p><p>In learning about how much time was spent on the Temporal API – no pun intended – I can’t help but feel in awe of the work that goes into web standards: all the discussion, scoping, writing, implementing, documenting, testing, and adopting that goes into making parts of the web better. And when a new standard is available and implemented, all developers can use it with their applications.</p><p>One thought I had at the conference is that I am starting to look forward to new releases in the browser. The more I learn about HTML, CSS, and native JavaScript APIs the more I am excited about the cutting edge. Anchor positioning is implemented in most major browsers. Work is being done on masonry layouts. The technology that powers the web is improving. Behind every change and improvement are people. State of the Browser uniquely brings together many people who make, use, and appreciate standards. I appreciate that I can go to the conference and hear stories from the people who are actively building the web platform.</p><p>Mike Hall’s talk “<a href="https://2026.stateofthebrowser.com/speaker/mike-hall/" rel="noreferrer">Lessons from building for the bottom of the web</a>” was all about his experience building a website that had to work with 2.5G connections. It was fascinating to hear the design considerations behind that. The project team wanted to deliver a web page that was no heavier than 128 KB, including images. They succeeded in their goal through many creative optimisations and technical decisions. It made me think about how light I could make a web page. What would an “ultra-light” version of a web page look like, I wonder?</p><p>I have lots to say about every talk I saw, but I will end by reflecting on one more talk: “<a href="https://2026.stateofthebrowser.com/speaker/chad-gowler/" rel="noreferrer">The Plateau of Accessibility Compliance: Where do we go from here?</a>” by Chad Gowler. This talk opened my mind to the work that is being done in the video games industry on accessibility. Gowler showed a video game that had an “arachnophobia mode” that allowed users to change the appearance of spiders if they preferred. In another example, Gowler showed the plethora of accessibility options made for one game – so many that the page kept going on and on as they scrolled through the instructions.</p><p>I loved the mix of talks, and thoroughly enjoyed meeting so many interesting people. Indeed, one of the best parts of the event is the conversations with other participants – at the start of the event, in the breaks, at lunch, and at the pub at the end of the day.</p><p>The synopsis for all the talks mentioned above is available on the <a href="https://2026.stateofthebrowser.com/">State of the Browser website</a>. I suspect talks will be available on the <a href="https://www.youtube.com/@londonwebstandards8403/videos">London Web Standards YouTube channel</a> at some point. Thanks to <a href="https://front-end.social/@dletorey">Dave</a> for organising the event, and for the whole team that made the event happen.</p><p>Tickets for the next event will be available on the <a href="https://2026.stateofthebrowser.com/2027/" rel="noreferrer">2027 State of the Browser website</a>. The in-person Super Organised Bird tickets have already sold out, but <a href="https://front-end.social/@dletorey/116160580794337220" rel="noreferrer">more tickets should be available soon</a>. </p>
Game Review: Unravel Two ★★★⯪☆ - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=680322026-03-03T12:34:43.000Z<p>My new year's resolution is to play more video games. Specifically <em>co-operative</em> games.</p>
<p><a href="https://shkspr.mobi/blog/2009/12/when-did-you-last-beat-your-wife/">I hate playing competitively</a>; it's rubbish to achieve victory at the expense of someone else. So <a href="https://mastodon.social/@Edent/116051890335937906">I asked for recommendations</a> and picked the cheapest thing that looked reasonable.</p>
<img src="https://shkspr.mobi/blog/wp-content/uploads/2026/02/UnravelTwo.webp" alt="Two string creatures help each other climb a hill." width="256" height="576" class="alignleft size-full wp-image-68033"/>
<p>Unravel Two is a little gem! It's a 2D platform puzzler dressed up in a 3D engine. You and your friend play little string creatures and have to work together to swing between points, lift objects, and pull each other over the lush scenery. It's the sort of physics-based game which could have been made for the 16-bit consoles of my childhood.</p>
<p>As befits a game this cheap and simple, it's fairly short. Once you've got the hang of the mechanics there are only a limited number of ways to solve each section. But it is great for shouting "No! Go left and pull!" or "We've got to time our jumps together" or "You stand on the button and I'll try swinging". It's also possible to temporarily switch to one-player mode - if one of you doesn't want to do the jumping puzzles, the other player can carry you.</p>
<p>Weirdly, the game is deeply portentous in a rather pointless manner. There's a story going on in the background about some kids who are either being abused, chased, or getting into trouble. It is utterly superfluous and detracts from the fun of the puzzles. Similarly, the level titles all have subtitles like "In which we find our way out of the sullen darkness and are redeemed." WTF? This is a silly game of string puppets - not every indie game needs to be "Life Is Strange"!</p>
<p>There's some replayability. You can see how quickly you can do the levels, there are some hidden collectables, and some extra challenge levels. Which, for <a href="https://store.playstation.com/en-gb/product/EP0006-CUSA10416_00-COLDWOODPIKE0000">£3.51 at time of writing</a> is more than reasonable.</p>
<p>A good casual co-op game - just ignore the vague story playing out behind the action.</p>
<iframe title="Unravel Two: Official Reveal Trailer | EA Play 2018" width="620" height="349" src="https://www.youtube.com/embed/j2TmLrTl6gs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>
Girl on a Divan by Berthe Morisot - James' Coffee Bloghttps://jamesg.blog/2026/03/03/girl-on-a-divan-by-berthe-morisot/2026-03-03T09:28:07.000Z
<p>Berthe Morisot’s <em>Girl on a Divan</em>, <a href="https://www.nationalgallery.org.uk/paintings/berthe-morisot-girl-on-a-divan">displayed in the National Gallery, London</a>, caught my eye as soon as I saw it. The painting was the last one I saw in the Impressionist room in the Gallery, but despite having been on my feet for hours before I stood for several minutes looking at the painting from all angles. There was something wonderful about the painting.</p><p><em>Girl on a Divan</em> portrays a woman gazing directly at the viewer. The woman’s expression is relaxed and friendly; the woman has a slight smile on her face. The woman is wearing a white dress with several stripes of colour. The stripes are somewhat incongruent with the white, not having any particular pattern. With that said, the stripes add to the depth of the image, and the colours of the stripes – mainly blue and orange – contrast well with the blue background.</p><p>In the middle ground, a shade of blue/green is used to create what could be a chair. This further adds depth to the painting. The woman has one arm raised slightly. Could the arm be resting on the arm of the chair?</p><p>I love the use of blue in this painting; the colours are both soft (through the shades chosen) and eye-catching (through the extensive use of blue for the background) at the same time.</p><p>The painting is made with sketch-like brushstrokes for the dress, background, and the hair; the face is more relatively detailed.</p><p>After several minutes of looking at the painting, I noticed a white dot in the left eye: a glimmer of light. This brought me a lot of joy. First, it took a while to notice this detail! I love “<a href="https://www.tate.org.uk/art/guide-slow-looking">Slow Looking</a>”. Second, after noticing the glimmer in the eye, I thought about how much it adds to the expression of the sitter.</p><p><em>Girl on a Divan</em> is now one of my favourite paintings.</p><p><em>I didn’t include a photo of the painting in this post for licensing reasons. You can see a </em><a href="https://www.nationalgallery.org.uk/paintings/berthe-morisot-girl-on-a-divan"><em>detailed photo of the painting on the National Gallery website</em></a><em>.</em></p>
How to change the Duolingo app icon - James' Coffee Bloghttps://jamesg.blog/2026/03/03/how-to-change-the-duolingo-app-icon/2026-03-03T09:03:20.000Z
<p>I am using Duolingo to learn a bit of German. I have been using the app for a while and enjoy the exercises. With that said, I am not a fan of Duolingo’s changing application icons on iOS.</p><p>I don’t like that an application can set its own home screen icon without my permission. I further do not appreciate that there doesn’t seem to be a way to change the app icon in some states. For example, there is an icon where the application mascot, Duo, appears with a plaster. I find the icon relatively distressing.</p><p>This weekend I figured out a workaround to reset the icon. Now, I have an Apple Shortcut that does one thing: open Duolingo. Because you can set custom icons for Apple Shortcuts and add them to your home screen, you can create a Shortcut that opens Duolingo using whatever icon you like, including the original application icon.</p><p>Here is what my Shortcut looks like on my home screen:</p><img alt="Two app icons on an iOS homescreen: Pocket Casts on the left, and Duolingo on the right." class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/IMG_4168-Large.jpeg" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/IMG_4168-Large.jpeg 600w, https://editor.jamesg.blog/content/images/size/w1000/2026/03/IMG_4168-Large.jpeg 1000w, https://editor.jamesg.blog/content/images/2026/03/IMG_4168-Large.jpeg 1206w"/><p>Whereas my current Duolingo app shows the plaster icon, my Shortcut shows the icon I chose.</p><p>This approach has a limit: because it isn’t the original application icon, I am unsure if you will see the red application notification icons on the icon. This is acceptable for my use of the app; my phone is mostly in Do Not Disturb so I don’t see the notification icons anyway.</p><p>Here is how the Shortcut is set up:</p><img alt="My Duolingo Shortcut with a single step: Open Duolingo." class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/IMG_4174-Large.jpeg" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/IMG_4174-Large.jpeg 600w, https://editor.jamesg.blog/content/images/size/w1000/2026/03/IMG_4174-Large.jpeg 1000w, https://editor.jamesg.blog/content/images/2026/03/IMG_4174-Large.jpeg 1206w"/><p>To change your app icon, create a new Shortcut with one step: to open an application. Choose Duolingo as the application to open. Set the name of the Shortcut to “Duolingo”. Next, <a href="https://cdn.jim-nielsen.com/ios/512/duolingo-2019-01-02.png">download a copy of the Duolingo app icon</a> and save it to your device.</p><p>Then, click the share icon in the Shortcuts application:</p><img alt="" class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/IMG_4169-Large.jpeg" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/IMG_4169-Large.jpeg 600w, https://editor.jamesg.blog/content/images/size/w1000/2026/03/IMG_4169-Large.jpeg 1000w, https://editor.jamesg.blog/content/images/2026/03/IMG_4169-Large.jpeg 1206w"/><p>Click “Add to Home Screen”:</p><img alt='The Share task tray with several buttons, including one that says "Add to Home Screen" indicated by a plus icon.' class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/IMG_4172-Large.jpeg" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/IMG_4172-Large.jpeg 600w, https://editor.jamesg.blog/content/images/size/w1000/2026/03/IMG_4172-Large.jpeg 1000w, https://editor.jamesg.blog/content/images/2026/03/IMG_4172-Large.jpeg 1206w"/><p>Click "Image" to choose a custom image as an icon:</p><img alt='The home screen icon editor interface. "Image" is selected, which has three options: Choose Photo, Take Photo, and Choose File.' class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/IMG_4173-Large.jpeg" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/IMG_4173-Large.jpeg 600w, https://editor.jamesg.blog/content/images/size/w1000/2026/03/IMG_4173-Large.jpeg 1000w, https://editor.jamesg.blog/content/images/2026/03/IMG_4173-Large.jpeg 1033w"/><p>Click “Choose Photo” if you saved the app icon as a photo. Choose the app icon you want to use. Then, click “Add” to add the shortcut to your device:</p><img alt="The Duolingo app icon is set in the home screen app icon preview page." class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/IMG_4171-Large.jpeg" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/IMG_4171-Large.jpeg 600w, https://editor.jamesg.blog/content/images/size/w1000/2026/03/IMG_4171-Large.jpeg 1000w, https://editor.jamesg.blog/content/images/2026/03/IMG_4171-Large.jpeg 1010w"/><p>You will now have a Duolingo app icon that looks like this:</p><img alt="My Duolingo shortcut." class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/IMG_4168-Large-1.jpeg" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/IMG_4168-Large-1.jpeg 600w, https://editor.jamesg.blog/content/images/size/w1000/2026/03/IMG_4168-Large-1.jpeg 1000w, https://editor.jamesg.blog/content/images/2026/03/IMG_4168-Large-1.jpeg 1206w"/><p>You can then remove the original Duolingo app from your home screen and keep your shortcut.</p><p>While this approach is a workaround, it satisfies the requirement of allowing me to use a custom Duolingo app icon.</p>
I wish there was a (simpler) way to highlight text in inputs - James' Coffee Bloghttps://jamesg.blog/2026/03/03/highlight-text-inputs-css/2026-03-03T08:42:25.000Z
<p>When I was building the search engine for my blog, one feature I wanted to implement was syntax highlighting within the search input field. I wanted special operators (i.e. <code>has:noalt</code>, which shows posts that contain one or more images without alt text) to have a different background colour indicating that a given segment of text had some semantic meaning.</p><p>Here is an example of the GitHub search feature which has semantic syntax highlighting:</p><img alt="" class="kg-image" loading="lazy" src="https://editor.jamesg.blog/content/images/2026/03/ghsearch.png"/><p>In the above image, the "capjamesg/indieweb-etherpad-archiver-v2" text is set in a light blue font; the text background is in a darker blue. This text is highlighted because it follows "repo:". This part of the query means that I want to scope my search to focus on a specific repository, "capjamesg/indieweb-etherpad-archiver-v2".</p><p>By highlighting the text that is part of the search query, I have a visual indication that what I have typed has some special meaning to the software.</p><p>Regex101 has a similar semantic syntax highlighting feature in the regular expression form field on their website:</p><img alt="" class="kg-image" loading="lazy" sizes="(min-width: 720px) 720px" src="https://editor.jamesg.blog/content/images/2026/03/regex101.png" srcset="https://editor.jamesg.blog/content/images/size/w600/2026/03/regex101.png 600w, https://editor.jamesg.blog/content/images/2026/03/regex101.png 726w"/><p>Various characters in the above screenshot appear with coloured backgrounds; each one has semantic meaning.</p><h2 id="the-status-quo">The status quo</h2><p>There doesn’t appear to be a semantic way to implement text highlighting in a native <code>input</code> tag. GitHub uses an <code>input</code> tag as the text and a lot of other code; a cursory read doesn’t make it obvious exactly what is going on. Regex101 uses a <code>contenteditable</code> div and gives every character in it a <code>span</code> tag. Both of these involve more code than I would like, all of which I would have to maintain.</p><p>I also explored an implementation of an <code>input</code> field that involved clipped background gradients, but there turned out to be many limits: maintaining state while scrolling, glitches in positioning the background, the requirement to use a monospaced font for the input so I can use <code>ch</code> to estimate where characters are in the input field.</p><h2 id="what-i-would-like">What I would like</h2><p>In my dream browser implementation, I would like to be able to apply the following styles:</p><ul><li>Text colour</li><li>Background colour</li></ul><p>I tried to use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API">CSS Custom Highlight API</a> on an <code>input</code> field but it didn’t work. It feels like this API could be a stepping stone to highlighting text in an <code>input</code> field?</p><p>For my use case, which is to style a text input field, I would like to be able to specify the character indices at which a highlight should start and end. I can then use JavaScript with my own grammar parser to determine what character indices should be highlighted, and in what colour (I may want to use one colour for filter keywords, for example, and another for sort keywords).</p><h2 id="security">Security</h2><p>I suspect there are security considerations for this idea: what if the <code>input</code> field has white text that hides from a user what is in the form field? A malicious site could make it seem like there is no text in a form field visibly even if there is such text. With that said, I wanted to write down my thoughts to start a discussion.</p><h2 id="related-discussions">Related discussions</h2><ul><li><a href="https://github.com/w3c/csswg-drafts/issues/4603" rel="noreferrer">CSS Working Group Issue #4603</a></li></ul>
22.00.0185 A security incident - Johnny.Decimalhttps://johnnydecimal.com/22.00.0185/2026-03-03T06:46:07.000Z<h1 id="a-security-incident">A security incident</h1>
<p>This morning I received an email from someone whose unique <code>johnnydecimal@example.com</code> address has received a PayPal phishing email. My personal address received the same email.</p>
<p>The email is from <code>no.con**star@ca**a.cl</code>. Its subject is <code>Please confirm your identity</code>.</p>
<p>I am investigating. If you received this email, please <a href="mailto:hello@johnnydecimal.com">forward it to me</a>.</p>
<hr>
<p><em>100% human. 0% AI. Always.</em></p>