Shellsharks Blogroll - BlogFlock https://blogflock.com/list/xJ8yq 2026-10-31T13:58:00.000Z BlogFlock shellsharks Discoverability Is Only Solved If You Can Be Discovered - Kev Quirk https://kevquirk.com/discoverability-is-only-solved-if-you-can-be-discovered 2026-10-31T13:58:00.000Z Kev Quirk <div class="link card"><h2>Discoverability Is Only Solved If You Can Be Discovered</h2><p class="post-author">by Widdershins</p><p>This is a follow up to <a href="https://kevquirk.com/socialspec-seems-pointless">my post</a> where Widdershins talks about how they agree with certain parts of my argument, but that the discoverability piece is flawed.</p><p><a class="button" target="_blank" href="https://widdershins.verja.net/discoverability-is-only-solved-if-you-can-be-discovered/">Read post ➡</a></p></div> <hr> <p>Saw this in my RSS feed and thought it was an interesting take that's worth sharing - also Widdershins' blog is excellent. I'd recommend adding it to your feed reader.</p> <p>I think the argument around other people controlling the gate to discoverability is a sound one, generally, but sites like <a href="https://bubbles.town" rel="noopener noreferrer">Bubbles</a> tend to add most sites, unless they're somehow obnoxious. So inclusion (and therefore discoverability) is only <a href="https://bubbles.town/faq" rel="noopener noreferrer">an email away</a>. Having said that, one person's obnoxious is another person's heaven, so it's all subjective.</p> <p>Either way, it's an interesting debate and I'm glad we're having it. Go check out Widdershins' blog too!</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:19gy@qrk.one?subject=Discoverability%20Is%20Only%20Solved%20If%20You%20Can%20Be%20Discovered">reply to this post by email</a>, or <a href="https://kevquirk.com/discoverability-is-only-solved-if-you-can-be-discovered#comments">leave a comment</a>.</p> </div> Open Tabs October 2026 - The Weblog of fLaMEd https://flamedfury.com/posts/open-tabs-october-2026/ 2026-10-31T13:00:07.000Z fLaMEd <p>What’s going on, Internet? If you don’t follow my <a href="https://flamedfury.com/bookmarks/">Bookmarks</a> through the <a href="https://flamedfury.com/feeds/">feed</a>, then here’s the bookmarks from October. Enjoy.</p> <p>Bit of a theme this month, the old web was messier and more fun, and running a site now keeps getting harder.</p> <ul class="list"> <li>Jenny O’Connor on <a href="https://gurlworld.com/the-internet-used-to-be-embarrassing-and-thats-why-it-was-good/" rel="noopener">why the embarrassing internet was the good internet</a>. My old fan pages agree.</li> <li>Winnie Lim on <a href="https://winnielim.org/journal/running-a-personal-website-is-not-fun-anymore/" rel="noopener">why running a personal website is not fun anymore</a>. Rough read. Between AI bots scraping the fuck out of the open web and hackers using AI agents to find holes, no wonder.</li> <li>Aaron’s <a href="https://earlyweblinks.com/" rel="noopener">Early Web Links</a> is a one-person directory of personal homepages, covering all types of personal websites.</li> <li>wulfpaper on <a href="https://wulfpaper.net/log/websites-shouldnt-be-hard/" rel="noopener">why making websites shouldn’t seem so hard</a>. Start with the writing, worry about code and design later.</li> <li><a href="https://divergentrays.com/graphics" rel="noopener">A big alphabetised list of old linkware webset graphics sites</a>. Handy if you’re after that old-school look.</li> </ul> <p>For more, check out the <a href="https://flamedfury.com/bookmarks/">bookmarks</a> archive, and subscribe to the <a href="https://flamedfury.com/feeds/">feeds</a> if you want these as they happen.</p> <p>Hey, thanks for reading this post in your feed reader! Want to chat? <a href="mailto:hello@flamedfury.com?subject=RE: Open Tabs October 2026">Reply by email</a> or add me on <a href="xmpp:flamed@omg.lol">XMPP</a>, or send a <a href="https://flamedfury.com/posts/open-tabs-october-2026/#webmention">webmention</a>. Check out the <a href="https://flamedfury.com/posts/">posts archive</a> on the website.</p> Gig Review: The Witcher in Concert ★★★★☆ - Terence Eden’s Blog https://shkspr.mobi/blog/?p=77063 2026-10-31T12:34:18.000Z Terence Eden’s Blog <p>The most common way people experience classical style music these days is via movies and video-games. After seeing <a href="https://shkspr.mobi/blog/2019/11/review-the-force-awakens-live-in-concert/">The Force Awakens - live in concert</a>, I've become rather a fan of watching movies performed with a live soundtrack.</p> <p>But what about watching a <em>video game</em> with orchestral accompaniment? We travelled up to Wolverhampton to see "The Witcher":</p> <blockquote><p>A one-of-a-kind live event that transforms the lasting legacy and emotional storytelling of The Witcher 3: Wild Hunt into an immersive concert</p></blockquote> <!-- 👋👋👋👋👋👋👋👋👋 Welcome to Comment Club! This top secret bonus material is only available to people who read my HTML comments. This was a TOP SECRET date with my wife. She didn't know what we were going to see or where we were going to see it. I'll admit, Wolverhampton isn't the most romantic destination for a mini-break! But the show was an excellent night out. What's the best concert you've been to with a date? OK, the three rules of comment club are… 1. You must not tell anyone about Comment Club - let them find out about it themselves. 2. You *must* add some Comment Club Content to at least one of your blog posts. Doesn't have to be much, just a little note will do. 3. You should drop an email to anyone whose comments you've read. Start by sending me a friendly message at comment.club@shkspr.mobi Keep looking out for more comments in future blog posts 😃 TTFN. --> <p>Obviously you can't have someone sat there with a PS5 controller while a band plays (although that'd be a hell of a Twitch stream!) instead a large screen projects various cut-scenes and in-game footage. It works pretty well - most of the popular scenes are in there (Geralt in the bathtub got a big cheer) although there was no hyper-extended Gwent session. The videos were a <em>little</em> repetitive. Some of the music is obviously composed to be swelling in the background and so repeated shots of swords looking cool or Geralt looking grumpy were sprinkled throughout.</p> <p>The highlight was seeing <a href="https://percival.pl/percival/?lang=en">Percival Schuttenbach</a> play a variety of instruments with absolute joy and gusto. The entire band look like they're having a whale of a time, and the conductor encouraged us to whoop and cheer for our favourite scenes (with perhaps a few boos for some of the more notorious enemies).</p> <p>As soundtracks go, it isn't particularly varied. There's a decent mix of tunes, some with singing, but they do tend to blur into one after a while. Nevertheless, a brilliant time for fans of the game who want to soak up the music.</p> <p>The Witcher in Concert is on tour around the world now.</p> <iframe title="The Witcher in Concert | Trailer" width="620" height="349" src="https://www.youtube.com/embed/VTsQzz2ukXA?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> <h2 id="pre-and-post-show"><a href="https://shkspr.mobi/blog/2026/10/gig-review-the-witcher-in-concert/#pre-and-post-show">Pre- and Post-Show</a></h2> <p>There was a merchandise stall hidden in one corner of the venue. Between doors opening and the start of the show (about an hour) a video looped through three screens - one of which encouraged up to share our photos with a hashtag. That's fine, but a few more videos wouldn't have gone amiss.</p> <p>After the show, the conductor said the band would stick around for selfies - which was nice of them.</p> <p>A touring show like this probably can't spare too much space for large scale models for people to pose with, or a couple of cosplayers to photograph, but it might have been nice if there were <em>something</em> to interact with before and after the show.</p> <img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=77063&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager"> Identity Assertion JWT Authorization Grant Draft 06 - Articles by Aaron Parecki https://aaronparecki.com/2026/10/30/19/oauth-id-jag-draft-06 2026-10-31T00:55:21.000Z Aaron Parecki <p>We've just published draft -06 of the Identity Assertion JWT Authorization Grant (ID-JAG):</p> <p><a href="https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/">https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/</a></p> <p>It's been great to see so many new implementations of ID-JAG over the past few months, across identity providers, authorization servers, clients and libraries. -05 and -06 are mostly about bringing what we've learned from these implementations back into the spec. The diff looks big, but most of it tightens the wording so independent implementations interoperate better. The flow and the overall design haven't changed.</p> <p>Most of the changes are clarifications, such as:</p> <ul> <li>How resource and audience values are compared and validated</li> <li>Which sub value the IdP selects for the Resource Authorization Server, and how subject identifiers are mapped</li> <li>Whose claims the ID-JAG carries (End-User, client, etc)</li> <li>How the Resource Authorization Server finds and validates the ID-JAG signing keys</li> <li>SAML <code>NameID</code> handling</li> <li>Using a Refresh Token as the subject token</li> <li>Error codes for common failure cases, and when a Client should request a new ID-JAG</li> <li>Fixes to examples and references</li> </ul> <p>A few changes are new, or make explicit what implementations were already doing:</p> <ul> <li>The IdP authenticates the Client at the Token Exchange step, and the request carries a single audience value</li> <li>When a subject token fails validation, the IdP now returns <code>invalid_request</code> instead of <code>invalid_grant</code>, as RFC 8693 requires. If you've implemented the Token Exchange step, please check your error handling.</li> <li>At the Resource Authorization Server, a key-bound ID-JAG can be used in place of client authentication</li> <li>mTLS is defined as another option besides DPoP for binding the ID-JAG</li> <li>New <code>id_jag_signing_alg_values_supported</code> IdP metadata</li> <li>A new Privacy Considerations section</li> </ul> <p>The full list is in the Document History section.</p> <p><a href="https://author-tools.ietf.org/iddiff?url1=draft-ietf-oauth-identity-assertion-authz-grant-04&url2=draft-ietf-oauth-identity-assertion-authz-grant-06">Diff from -04</a></p> <p>Thanks to everyone who has been implementing this and sending feedback, and especially to <a href="https://notes.karlmcguinness.com/">Karl</a> for working through so many of the issues. I'm hoping to get time at IETF 127 to go over the remaining open issues. In the meantime, comments are welcome on the list or at <a href="https://github.com/oauth-wg/oauth-identity-assertion-authz-grant">https://github.com/oauth-wg/oauth-identity-assertion-authz-grant</a></p> Morning - James' Coffee Blog https://jamesg.blog/2026/10/31/morning 2026-10-31T00:00:00.000Z James' Coffee Blog <p>A golden glow peeked through the edges of the curtains. <em>What colour is the sky this morning?</em>, I wondered, knowing in the back of my mind that the colours may only be there for a few more minutes – such is the pace of the sunrise. No moment can be taken for granted. I opened the curtains and saw a salmon-esque glow in the sky: not quite pink, but not quite orange: a mix of both colours. The sun was rising in the opposite direction, at the stage where the whole landscape seems transformed by ephemeral colours.</p> <p>I later thought about how the landscape is always changing with the day – the sunrise on a relatively clear day like this morning’s, where the sky was only dotted with clouds, brought forth the aforementioned pink-ish colour, and golden colours, too. Trees not yet touched by the sunlight had a faint patina, as if they were in a Renaissance painting that had long since aged. But these trees were real, right in front of me, bathing in the rhythms of the day.</p> <p><em>If only I could describe the trees with the same precision of a painting.</em></p> <p>Was that an eagle, soaring through the field? I haven’t seen one as long as I could remember. The interlaying golden light rises from the distance; the streams in the valley were woken on their own accord, always flowing, for the sparkling sunlight has not shone on them yet. I watched the landscape with wonder, as I always do.</p> <p style="text-align: center;">⁂ ⁂ ⁂</p> <p>I went on a long walk today, to make up for the time lost from last weekend where I stayed mostly indoors to weather the storm. The last week has been one of missed routines and reminding myself that <em>this too shall pass.</em> While last night I sat by my piano playing sad songs, later resting my tired head between my arms on top of the keys, this morning I woke up with newfound energy and vigour. I can never remember exactly how I get better when I feel down, but going out for a walk surely helped.</p> <p><em>The morning sky ushered forth darkness’ bye.</em></p> <p>In the park, I walked on wood chips sprinkled with yellow trees under relatively low canopies. The path on which I walked was only meters away from the concrete one with which I was more familiar, but I wanted to feel something new under my feet – to get closer to the ground; to feel whether the wood chips would be softer than the concrete. Although I was so close to the concrete path, what was ahead was different, the sounds and sensations of the ground were different; the view of the sky, intermediated by low hanging yellow and orange and green leaves, is new.</p> <p>I walked for miles, finding a rhythm that meant I was walking up the hilly streets faster than I expected. At one point, I stopped at a gallery window to admire an artist whose works depicted landscapes over the sea. The pink and orange and blue colours were breathtaking, the kind of works that stop you in their tracks. The gallery was one where works were for sale. It makes me think about how much I love that there are still new artists making works. I don’t know if the works I saw today were new, but they did feel more contemporary, capturing the world in a different way to pieces I have seen in museums.</p> <p><em>A man walking down the street wore a shirt that caught my eye. “Creatives are the new athletes.”</em></p> <script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a5339f26abb490cb',t:'MTc5MzQ1OTc5NA=='};var l=window.parent.location,o;try{o=new URL(l.origin).origin}catch(e){try{o=new URL(new URL(l.href).origin).origin}catch(e){o=''}}var u='/cdn-cgi/challenge-platform/scripts/jsd/main.js?ray=a5339f26abb490cb',a=document.createElement('script');a.src=o?new URL(u,o).href:u;document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script> Note published on October 30, 2026 at 10:13 PM UTC - Molly White's activity feed 6ae516a1b6faaacba7234ee5 2026-10-30T22:13:53.000Z Molly White <article><div class="entry h-entry hentry"><header></header><div class="content e-content"><p>In July 2024, I <a href="https://www.citationneeded.news/coinbase-campaign-finance-violation/">reported</a> that Coinbase appeared to be violating campaign finance law by making contributions while holding federal contracts. I filed an <a href="https://www.citizen.org/wp-content/uploads/coinbase-fec-complaint.pdf">FEC complaint</a> alongside Public Citizen. The FEC hasn’t acted. Since, Coinbase has given $60M more and landed another federal contract. </p><p>Coinbase responded to the initial complaint by arguing that, despite having received a federal contract, they were not a federal contractor — then insinuated I had secret funders and made lightly veiled legal threats against me. </p><p>“It’s bad enough when the laws are weak or there are loopholes in the law, but it’s almost worse when you have laws on the books that aren’t being enforced because the regulator is inadequate, and that’s the situation where we’re finding ourselves now,” said Eric Petry, counsel in the Brennan Center for Justice’s elections and government program.</p><p>I track <a href="https://influence.citationneeded.news/2026/companies/coinbase">Coinbase’s (and its top executives’) campaign spending</a>. They’ve <a href="https://influence.citationneeded.news/analysis/quidproquo#coinbase">spent $100 million+ since 2024</a> across super PACs, Trump campaign committees, and other individual candidates.</p><div class="media-wrapper"><a href="https://storage.mollywhite.net/micro/287c74952e9962db84d9_Screenshot-2026-10-30-at-6.06.13---PM.png" data-fslightbox=8ab6958b951e14160334><img src="https://storage.mollywhite.net/micro/287c74952e9962db84d9_Screenshot-2026-10-30-at-6.06.13---PM.png" alt="Entity: Coinbase Benefit to entity SEC enforcement case dismissed with prejudice Relaunched bitcoin borrowing program previously shut down after SEC warnings SEC statement that staking services are not within their jurisdiction CFTC amicus brief looking to shield prediction markets from state regulation Coinbase unilaterally blocked the Clarity Act in the Senate Banking Committee, demanding changes to stablecoin revenue provisions and more authority given to the CFTC Benefit to Trump and family $56.17 million to crypto-focused super PACs (2026 cycle) $46.5 million to crypto-focused super PACs (2024 cycle) $2.24 million to Senate super PACs (2026 cycle) $1.95 million to Trump’s campaign, inauguration, and pro-Trump PACs (since 2024) $1.15 million to House super PACs (2026 cycle) $1 million to Senate super PACs (2024 cycle) $11,775 to Stand With Crypto's dark money arm (2024 cycle) Sponsored Trump's military parade Contributed to fund Trump's $300 million ballroom project " /></a></div><div class="related-post"><div class="article h-cite hcite"><div class="title"><a class="u-url u-repost-of u-in-reply-to" href="https://www.washingtonsun.com/influence/coinbase-marshal-service-contract-political-contributions" rel="bookmark">“<span class="p-name">Coinbase Scored Another Federal Contract. Does That Make Its Campaign Contributions Illegal?</span>”</a></div><div class="byline"><span class="p-author h-card">Taylor Giorno</span> in <i class="p-publication">The Washington Sun</i>. <span class="read-date"></span></div><blockquote class="summary p-summary entry-summary">Since 2024, the FEC has failed to rule on a complaint against Coinbase, which says it's done nothing wrong.</blockquote></div></div></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp-block"><div class="timestamp">Posted: <a class="u-url" href="https://www.mollywhite.net/micro/entry/202610301811"><time class="dt-published" datetime="2026-10-30T22:13:53+00:00" title="October 30, 2026 at 10:13 PM UTC">October 30, 2026 at 10:13 PM UTC</time>. </a></div></div><div class="social-links"> <span> Also posted to: </span><a class="social-link u-syndication mastodon" href="https://hachyderm.io/@molly0xfff/117532159876328237" title="Mastodon" rel="syndication">Mastodon, </a><a class="social-link u-syndication bluesky" href="https://bsky.app/profile/molly.wiki/post/3mz4po35qc226" title="Bluesky" rel="syndication">Bluesky</a></div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/micro/tag/campaign_finance" title="See all micro posts tagged "campaign finance"" rel="category tag">campaign finance</a>, <a class="tag p-category" href="https://www.mollywhite.net/micro/tag/coinbase" title="See all micro posts tagged "Coinbase"" rel="category tag">Coinbase</a>, <a class="tag p-category" href="https://www.mollywhite.net/micro/tag/corruption" title="See all micro posts tagged "corruption"" rel="category tag">corruption</a>, <a class="tag p-category" href="https://www.mollywhite.net/micro/tag/us_politics" title="See all micro posts tagged "US politics"" rel="category tag">US politics</a>. </div></div></footer></div></article> Published on Citation Needed: "It’s always North Korea" - Molly White's activity feed 6ae4cdfc2be334bbcec5f763 2026-10-30T17:03:56.000Z Molly White <article class="entry h-entry hentry"><header><div class="description">Published an issue of <a href="https://www.citationneeded.news/"><i>Citation Needed</i></a>: </div><h2 class="p-name"><a class="u-syndication" href="https://www.citationneeded.news/its-always-north-korea" rel="syndication">It’s always North Korea </a></h2></header><div class="content e-content"><div class="media-wrapper"><a href="https://www.citationneeded.news/its-always-north-korea"><img src="https://www.citationneeded.news/content/images/2026/10/dprk-binance.png" alt="A person in a black hoodie with their face in shadow sits at a computer with the Binance logo on the back. Behind them is a DPRK flag."/></a></div><div class="p-summary"><p>Answering your questions about who was behind the Binance hack, how they launder the money, and where it goes</p></div></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <a class="u-url" href="https://www.citationneeded.news/its-always-north-korea"><time class="dt-published" datetime="2026-10-30T17:03:56+00:00" title="October 30, 2026 at 5:03 PM UTC">October 30, 2026 at 5:03 PM UTC</time>. </a></div><div class="social-links"> </div></div><div class="bottomRow"><div class="tags"></div></div></footer></article> SocialSpec Seems...Pointless - Kev Quirk https://kevquirk.com/socialspec-seems-pointless 2026-10-30T16:36:00.000Z Kev Quirk <p>I've seen a few people talking about <a href="https://socialspec.org/" rel="noopener noreferrer">SocialSpec</a> which claims that <em>"the future of social media is websites"</em>. Something I strongly agree with. However, I don't see the point of this fledgling spec on top of all the other IndieWeb complexity that's flying around.</p> <p>From what I can gather, it's 3 files that you upload to <code>/.well-known</code> which provide a bio, a means of contact, and what blogs you follow. Step one is to have an RSS feed, actually, but <a href="https://kevquirk.com/please-add-rss-support-to-your-site/">everyone should have an RSS feed anyway</a>. But aside from this, I already have <a href="https://kevquirk.com/about">a bio</a>, <a href="https://kevquirk.com/contact">a means of contact</a>, and a list of <a href="https://kevquirk.com/blogroll">blogs I follow</a>. So what is SocialSpec trying to achieve?</p> <p>Again, from what I can gather from the site, you publish these 3 files on your site and you're magically enrolled in the new <em>website social network</em>. Where you can peruse a timeline of posts from fellow bloggers, based on who you follow in your OPML file.</p> <p>Fuck yeah! Win for the open web. Sign me up!</p> <p>But hang on a second. This <em>open spec</em>, based on <em>open protocols</em>, for the <em>open web</em> doesn't even have a web app. Nope. The only client that actually uses it is sitting behind a fucking iOS app.</p> <p>Now I'm sure other apps will come with time, but if this were truly a platform for the open web, wouldn't a website that supports a PWA have been a better solution initially? I think so.</p> <h2>What does it solve?</h2> <p>Even if someone takes the time to publish and maintain these files, what does <em>SocialSpec</em> offer over an RSS feed reader, and a couple of pages on your site?</p> <p>Nothing.</p> <p>I like how people are thinking of ways to interconnect sites in this way, but I don't think this is the right approach. It's trying to solve a problem that doesn't really exist in my opinion. The only issue it <em>may</em> fix is discoverability. But I still think it's flawed as the service would need a decent user base to make discoverability viable.</p> <p>Sites like <a href="https://bubbles.town/" rel="noopener noreferrer">Bubbles</a>, <a href="https://powrss.com/" rel="noopener noreferrer">PowRSS</a>, and <a href="https://bearblog.dev/discover/" rel="noopener noreferrer">Bear Discover</a> are far better than this solution as they're easier to use and have no barrier for entry.</p> <p>Maybe I'm being a curmudgeon here, but I really don't get it. This is a solved problem, and has been for decades.</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:19gy@qrk.one?subject=SocialSpec%20Seems...Pointless">reply to this post by email</a>, or <a href="https://kevquirk.com/socialspec-seems-pointless#comments">leave a comment</a>.</p> </div> Notable links: October 30, 2026 - Werd I/O 6ae4ba3055c15e0001ad082f 2026-10-30T15:55:30.000Z Werd I/O <img src="https://storage.ghost.io/c/18/7c/187cc681-d3f3-49fc-87de-b01d06b76821/content/images/2026/10/getty-images-eFiENE6KwGE-unsplash.jpg" alt="Notable links: October 30, 2026"><p><em>Most Fridays, I share a handful of pieces that caught my eye at the intersection of technology, media, and society.</em></p><p><em>Did someone forward this to you? </em><a href="https://werd.io/notable-links-september-23-2026/#/portal" rel="noreferrer"><em>Subscribe for free</em></a><em>.</em></p><hr><h3 id="chatgpt-is-building-detailed-psychological-profiles-of-its-users"><a href="https://futurism.com/artificial-intelligence/chatgpt-building-profiles-users" rel="noreferrer">ChatGPT Is Building Detailed Psychological Profiles of Its Users</a></h3><p>It probably shouldn’t be a surprise that chatbots like ChatGPT are profiling their users. Still, there are some surprising numbers here:</p><blockquote>“A staggering 96 percent of memories were created unilaterally by the chatbot, according to the study, meaning that the users had little overt control over the data points that ChatGPT logged as their interactions wore on. Stored memories were also deeply revealing about users. About 28 percent of the memories examined contained personal data as defined by Europe’s strict General Data Protection Regulation standards, and 52 percent contained rich “psychological insights” about users.”</blockquote><p>I think back to Gina Chua and Adiel Kaplan’s <a href="https://www.journalismfutures.org/three-layer-cake">three-layer cake analogy for the AI stack</a>. In their analysis, the <em>consumption</em> layer profiles the user; this new report makes clear how deep that profiling goes.</p><p><a href="https://werd.io/news-will-be-intermediated-by-ai-whats-next/">As I said in my commentary then</a>:</p><blockquote>“Profile data is accumulated, private, and usually non-portable. The consumption layer also represents the greatest risk to creators from platform business decisions, both in terms of the business models of those platforms and which creators they choose to feature. Open portability standards and protocols — combined with full user control of their data — can scale, create useful competition, and empower users in the process.”</blockquote><p>Nothing here dissuades me from that view. To be as useful as possible, AI tools need to dig into our most personal information, make inferences about who we are and what’s interesting to us, and maintain highly personal profiles. Our AI agents are not some kind of trusted friend: they are products owned by a third party that needs to justify a trillion dollar valuation and may not have our best interests at heart. All the major vendors provide services used by the military and law enforcement. What happens if one of those agencies wants to get hold of that profile information? These companies simply cannot be trusted with our most private information, and should not have access to it.</p><p>But, of course, legislators have also been negotiated into a position of alignment with AI accelerationism. We need to gather all of this personal information about individuals in a supposed democracy, they argue, because otherwise China will win! These concerns seem to trump the fact that privacy is considered <a href="https://en.wikipedia.org/wiki/Right_to_privacy">a fundamental human right</a>, for very solid and defensible reasons: it makes dissent, organizing, a free press, and a well-lived life possible.</p><p>I am not arguing that there are not legitimate uses for AI or that the technology is not transformative. But there should not be an argument that we should let go of our core human values or the fundamental protections needed to maintain a robust democracy — of which privacy is one — because this tech is cool and we need it to grow really fast and by the way it’s also now <a href="https://www.washingtonpost.com/technology/2026/10/07/ai-is-propping-up-economy-including-manufacturing-ads-energy/">propping up our economy</a>. Trading privacy for growth is not a smart long-term strategy: it will bite us.</p><p>As individuals, we can protect ourselves by using different tools. But privacy is a group inoculation. If the chatbot is profiling its users, I suspect it’s also profiling the people its users are talking about. We need to demand better behavior from our vendors while taking steps to also demand it from our friends.</p><hr><h3 id="manifestos-fear-and-%E2%80%98loser-thinking%E2%80%99-inside-proton%E2%80%99s-ai-reckoning"><a href="https://www.404media.co/manifestos-fear-and-loser-thinking-inside-protons-ai-reckoning/" rel="noreferrer">Manifestos, Fear, and ‘Loser Thinking’: Inside Proton’s AI Reckoning</a></h3><p>Proton, based in Switzerland, offers encrypted email, file storage, calendars, and more. It markets itself as a privacy-oriented alternative to Google Workspace, based in a neutral territory that is generally outside of the jurisdiction of the United States. I’ve generally been glad that it exists — but stories like this give me pause.</p><p><a href="https://www.404media.co/manifestos-fear-and-loser-thinking-inside-protons-ai-reckoning/">404 Media reports</a>:</p><blockquote>“Our reporting also paints a picture of Proton that is likely very different to the public’s perception of a company with a goal of carefully protecting privacy: one that in reality is barreling ahead with AI as quickly as possible so it can achieve the explicit goal of more annual revenue.”</blockquote><p>CEO Andy Yen comes across as a bully who is pushing his staff to adopt AI as quickly as possible in order to maximize Proton’s revenue because its ARR was slipping. That’s not an approach you would hope a security-oriented, encryption-based organization would take.</p><p>This follows an unwise decision <a href="https://theintercept.com/2025/01/28/proton-mail-andy-yen-trump-republicans/">to praise a Trump nomination at the beginning of his second administration</a>. Yen said it wasn’t intended as a political statement. I don’t think that he’s necessarily a Trump supporter, but it was part of a series of incidents that follow a troubling pattern: an action that undercuts Proton’s brand and stated values, followed by defensive excuses. It <a href="https://theintercept.com/2025/09/12/proton-mail-journalist-accounts-suspended/">suspended journalist accounts at the request of a cybersecurity agency</a> and then called the outcry “blown out of proportion”; it <a href="https://www.theregister.com/2024/05/13/infosec_in_brief/">handed over the recovery email address for a Catalan activist</a>, an iCloud address that led to Apple providing their full personal information, and said its hands were tied.</p><p>And then there’s this:</p><blockquote>“Andy Yen, the CEO of Proton, had a message for an employee in the company’s security Slack channel who urged the company to at least take a few days to pentest newly written code before pushing it live. “That’s bullshit and loser thinking. Of course it’s possible to be fast and secure,” Yen wrote in the channel at the end of August. “Stop thinking always of how to be slower, and focus more on how to be faster.””</blockquote><p>Services like Proton need to exist. Privacy is an important prerequisite to democracy: it protects journalists, activists, vulnerable communities, and everyone’s ability to live well and with dignity. But it’s a serious business. A move-fast culture of bullying that apes startup-land and calls caution “loser thinking” does not instill confidence, and implies it’s only a matter of time before something much worse happens.</p><hr><h3 id="its-offensively-cheap-how-solar-power-is-quietly-becoming-bigger-than-nuclear"><a href="https://www.bbc.com/future/article/20261023-how-solar-became-bigger-than-nuclear" rel="noreferrer">'It's offensively cheap': How solar power is quietly becoming bigger than nuclear</a></h3><p>This is something we should all be excited about:</p><blockquote>“The world's solar power is crossing a threshold. A decade ago, it barely registered on a global scale, providing just 1% of the world's power. In 2026, it will almost certainly increase to 10% of power, and overtake nuclear, a mainstay of electricity since the late 1970s.”</blockquote><p>Solar energy is abundant, and the cheaper and more efficient it gets, the more electricity there will be to power anything we want. On that level alone, we should be cheering for its success.</p><p>But the other property solar energy has is relative decentralization. While not anyone can <em>build</em> a solar panel, anyone can plug one in — and, obviously, the sun belongs to everyone. It represents real energy independence, not just internationally, but from large energy companies (at every level from fossil fuel multinationals to utilities) that have <a href="https://www.desmog.com/2021/10/29/dirty-dozen-documents-big-oil-secret-climate-knowledge-part-1/">enjoyed enormous influence for over a century</a>.</p><p>Or it should. Energy companies <a href="https://azpm.org/s/66276-arizona-utility-finally-comes-clean-about-political-spending/">have sponsored laws, rules, and regulations</a> in the US <a href="https://www.energias-renovables.com/autoconsumo/iberdrola-la-compania-que-ideo-el-impuesto-20220621-1">and elsewhere</a> that have made it harder for people to plug solar in. Those should be defeated, and our electrical systems should be upgraded to take decentralized solar into account.</p><p>But the power dynamics don’t end at the influence of energy companies: a large share of the polysilicon in solar panels is produced in Xinjiang, where there have been well-documented allegations of <a href="https://shura.shu.ac.uk/29640/">forced labor of Uyghurs and other minority groups</a>. Batteries often contain cobalt, which is dug from the Democratic Republic of Congo, <a href="https://www.npr.org/sections/goatsandsoda/2023/02/01/1152893248/red-cobalt-congo-drc-mining-siddharth-kara">often by hand and often by children and slaves</a>. They also contain lithium, drawn from brine operations that <a href="https://e360.yale.edu/features/lithium-mining-water-andes-argentina">drain water from Indigenous communities in the Andes</a>.</p><p>The next frontier needs to be freeing these technologies from harm — and there’s a long way to go. There’s some promise from tech like <a href="https://www.mining.com/web/energy-storage-boom-drives-battery-shift-leaving-nickel-cobalt-behind/">nickel-and-cobalt-free LFP batteries</a>, more ethical lithium extraction, and recycling, but these need further investment, and the underlying issues require sustained attention. There is an energy revolution, but everyone should see the benefits.</p><hr><h3 id="and-more">And more:</h3><p>Here are some of the articles I didn't get a chance to go into in depth this week.</p><h4 id="it%E2%80%99s-now-official-tech-is-the-new-tobacco"><a href="https://cailinoconnor.substack.com/p/its-now-official-tech-is-the-new" rel="noreferrer">It’s now official, tech is the new tobacco</a></h4><p>Following in the footsteps of tobacco and the fossil fuels industry, tech companies have been sponsoring academic research that conveniently produces findings in their favor, while working hard to discredit research that might undermine their businesses. Internal documents from Meta, made public through an ongoing lawsuit against them, confirm it.</p><h4 id="the-subculture-flywheel"><a href="https://pointc.co/the-subculture-flywheel/" rel="noreferrer">The Subculture Flywheel</a></h4><p>In common with all of <a href="https://pointc.co" rel="noreferrer">Corey Ford</a>'s guides, this is an easy-to-follow way to build culture and practices in your team that further the values and outcomes you want to see. It's simple, human, and effective.</p><h4 id="silicon-valley-wants-you-to-invest-in-miracles"><a href="https://www.theverge.com/ai-artificial-intelligence/1023070/anthropic-ipo-risk-factors-filing-miracles" rel="noreferrer">Silicon Valley wants you to invest in miracles</a></h4><p>Anthropic's S-1 filing is bananas. It's openly cult-like: it wants you to "be part of something bigger" that, by the way, might destroy humanity. As one Wall Street leader put it to me this week: either they're lying about the impact and they shouldn't be allowed to go public, or they're telling the truth about the impact and they shouldn't be allowed to go public. Also, they acknowledge that they might never be a viable business. Fun times.</p> Book Review: The God of Small Things by Arundhati Roy ★★☆☆☆ - Terence Eden’s Blog https://shkspr.mobi/blog/?p=76302 2026-10-30T12:34:22.000Z Terence Eden’s Blog <img src="https://shkspr.mobi/blog/wp-content/uploads/2026/10/gost.webp" alt="Book cover." width="200" class="alignleft"> <p>I did not care for this one bit. I found it cloying, infantilising, and far too circuitous.</p> <p>It starts off as a bit of an overwritten melodrama, where every phrase is a delicious flower waiting to bloom, but ends up being a over-sugared mess with a rotten heart. Parts are just exhausting to read, with no time to catch your breath between scenes. That can work in some books when spaced out - here I just found it annoying.</p> <p>My main problem with it, though, is that it feels like it is <em>entirely</em> exposition. Because of the (unnecessarily) jumbled order of the story, every paragraph feels like it is introducing us to something or someone. Rather than progress the plot, I felt like I was being drip-fed morsels for what was coming up. In the end, the story just isn't interesting enough to support that.</p> <p>Parts of the writing are gorgeous, but they're in service of so little that it seems like an unfair sleight of hand; you're too busy admiring the prose to realise how dull and uneventful everything is. The repetition hammers away like a vocal tic - wearing out its welcome by the tenth occurrence. The mannered spelling, punctuation, and extemporising is similarly grating after a while.</p> <p>I don't mind characters being unsympathetic - but every single one is painted as a monster or a simpleton. It's hard to keep reading when nearly all the main characters are so relentlessly unlikeable. I know I'm not a big fan of sad or upsetting books, but there was so <em>little</em> joy or happiness in this one that I felt grimy reading it. Afterwards I was left wondering what the point of it was. I do not doubt that the depictions of casteism were well done but, again, to what end?</p> <p>I read this for a book club and wondered what my fellow readers made of it. All of us found it a challenging read, with most raising similar criticisms to mine. We all found the prose to be beautiful but the plot lacking. Only one of use gave it a positive review - but we all agreed it was a fascinating book to discuss.</p> <p>Perhaps we were all just philistines? Yet each of us came up with a compelling reason why we found it so unpalatable. There truly was something for everyone to complain about.</p> <img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=76302&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager"> Weeknote #2024 - Robb Knight • Posts • Atom Feed https://rknight.me/blog/weeknote-2024/ 2026-10-30T11:06:00.000Z Robb Knight <p><a href="https://titleart.dvy.io">WordArt is back, baby</a>.</p> <figure><img src="https://cdn.rknight.me/site/2026/weeknotes-2024.jpg" alt="Weeknotes 2024 written in WordArt" /></figure> <p>This is fun. Put in a postcode or area and <a href="https://edjefferson.com/localwiki/">Local Wikipedia</a> shows you articles local to you.</p> <p><a href="https://www.postmarkgames.com/games">Postmark</a> make games that are printable and just need common game components like cards or dice to play. Neat.</p> <p>Wonders of Web Weaving, a podcast I was a guest on back <a href="https://rknight.me/blog/i-was-a-guest-on-web-weaving/">in August</a>, has <a href="https://web-weaving.jamesg.blog/25">just published it's 25th and final episode</a>. James has some <a href="https://jamesg.blog/2026/10/27/www-bts">behind the scenes</a> info here about the show.</p> <p><a href="https://shep.online">Shep</a>, a prolific maker of web things, posted about <a href="https://instantfail.me">Instant Fail</a> which is a soundboard of fail sounds and that led me to find his <a href="https://dumbfun.lol/F16bit/">F16 Bit</a> project — "<em>Real Formula 1 race data, redrawn as a 16-bit arcade broadcast</em>". So good.</p> <p><a href="https://www.youtube.com/watch?v=Z-NTmezsVds">Stupid game trailer made me feel things</a>.</p> <p>Lou <a href="https://mastodon.social/@loucyx/117516068666699626">reminded me I needed to do my llms.txt</a>. So <a href="/llms.txt">I did</a>.</p> <p>The <a href="https://www.youtube.com/watch?v=nIw1O3zvOfE">trailer for the new Jumanji</a> dropped and it looks as stupid as ever. I can't wait.</p> <p>I learned about <a href="https://www.psalty.com">Psalty</a> and I can never unsee it.</p> Proton is AI-pilled and calls caution "loser thinking". - Werd I/O 6ae40e3c55c15e0001ad06e9 2026-10-30T03:25:48.000Z Werd I/O <p>Link: <a href="https://www.404media.co/manifestos-fear-and-loser-thinking-inside-protons-ai-reckoning/"><em>Manifestos, Fear, and ‘Loser Thinking’: Inside Proton’s AI Reckoning, by Joseph Cox at 404 Media</em></a></p><p>Proton is a service based in Switzerland that offers encrypted email, file storage, calendars, and more. It markets itself as a privacy-oriented alternative to Google Workspace, based in a neutral territory that is generally outside of the jurisdiction of the United States. I’ve generally been glad that it exists — but stories like this give me pause.</p><p><a href="https://www.404media.co/manifestos-fear-and-loser-thinking-inside-protons-ai-reckoning/">404 Media reports</a>:</p><blockquote>“Our reporting also paints a picture of Proton that is likely very different to the public’s perception of a company with a goal of carefully protecting privacy: one that in reality is barreling ahead with AI as quickly as possible so it can achieve the explicit goal of more annual revenue.”</blockquote><p>CEO Andy Yen comes across as a bully who is pushing his staff to adopt AI as quickly as possible in order to maximize Proton’s revenue because its ARR was slipping. That’s not an approach you would hope a security-oriented, encryption-based organization would take.</p><p>This follows an unwise decision <a href="https://theintercept.com/2025/01/28/proton-mail-andy-yen-trump-republicans/">to praise a Trump nomination at the beginning of his second administration</a>. Yen said it wasn’t intended as a political statement. I don’t think that he’s necessarily a Trump supporter, but it was part of a series of incidents that follow a troubling pattern: an action that undercuts Proton’s brand and stated values, followed by defensive excuses. It <a href="https://theintercept.com/2025/09/12/proton-mail-journalist-accounts-suspended/">suspended journalist accounts at the request of a cybersecurity agency</a> and then called the outcry “blown out of proportion”; it <a href="https://www.theregister.com/2024/05/13/infosec_in_brief/">handed over the recovery email address for a Catalan activist</a>, an iCloud address that led to Apple providing their full personal information, and said its hands were tied.</p><p>And then there’s this:</p><blockquote>“Andy Yen, the CEO of Proton, had a message for an employee in the company’s security Slack channel who urged the company to at least take a few days to pentest newly written code before pushing it live. “That’s bullshit and loser thinking. Of course it’s possible to be fast and secure,” Yen wrote in the channel at the end of August. “Stop thinking always of how to be slower, and focus more on how to be faster.””</blockquote><p>Services like Proton need to exist. Privacy is an important prerequisite to democracy: it protects journalists, activists, vulnerable communities, and everyone’s ability to live well and with dignity. But it’s a serious business. A move-fast culture of bullying that apes startup-land and calls caution “loser thinking” does not instill confidence, and implies it’s only a matter of time before something much worse happens.</p> Proton is AI-pilled and calls caution "loser thinking". - Werd I/O 6ae40cc055c15e0001ad06d1 2026-10-30T03:21:00.000Z Werd I/O <p>Link: <a href="https://www.404media.co/manifestos-fear-and-loser-thinking-inside-protons-ai-reckoning/" rel="noreferrer"><em>Manifestos, Fear, and ‘Loser Thinking’: Inside Proton’s AI Reckoning, by Joseph Cox at 404 Media</em></a></p><p>Proton, based in Switzerland, offers encrypted email, file storage, calendars, and more. It markets itself as a privacy-oriented alternative to Google Workspace, based in a neutral territory that is generally outside of the jurisdiction of the United States. I’ve generally been glad that it exists — but stories like this give me pause.</p><p><a href="https://www.404media.co/manifestos-fear-and-loser-thinking-inside-protons-ai-reckoning/">404 Media reports</a>:</p><blockquote>“Our reporting also paints a picture of Proton that is likely very different to the public’s perception of a company with a goal of carefully protecting privacy: one that in reality is barreling ahead with AI as quickly as possible so it can achieve the explicit goal of more annual revenue.”</blockquote><p>CEO Andy Yen comes across as a bully who is pushing his staff to adopt AI as quickly as possible in order to maximize Proton’s revenue because its ARR was slipping. That’s not an approach you would hope a security-oriented, encryption-based organization would take.</p><p>This follows an unwise decision <a href="https://theintercept.com/2025/01/28/proton-mail-andy-yen-trump-republicans/">to praise a Trump nomination at the beginning of his second administration</a>. Yen said it wasn’t intended as a political statement. I don’t think that he’s necessarily a Trump supporter, but it was part of a series of incidents that follow a troubling pattern: an action that undercuts Proton’s brand and stated values, followed by defensive excuses. It <a href="https://theintercept.com/2025/09/12/proton-mail-journalist-accounts-suspended/">suspended journalist accounts at the request of a cybersecurity agency</a> and then called the outcry “blown out of proportion”; it <a href="https://www.theregister.com/2024/05/13/infosec_in_brief/">handed over the recovery email address for a Catalan activist</a>, an iCloud address that led to Apple providing their full personal information, and said its hands were tied.</p><p>And then there’s this:</p><blockquote>“Andy Yen, the CEO of Proton, had a message for an employee in the company’s security Slack channel who urged the company to at least take a few days to pentest newly written code before pushing it live. “That’s bullshit and loser thinking. Of course it’s possible to be fast and secure,” Yen wrote in the channel at the end of August. “Stop thinking always of how to be slower, and focus more on how to be faster.””</blockquote><p>Services like Proton need to exist. Privacy is an important prerequisite to democracy: it protects journalists, activists, vulnerable communities, and everyone’s ability to live well and with dignity. But it’s a serious business. A move-fast culture of bullying that apes startup-land and calls caution “loser thinking” does not instill confidence, and implies it’s only a matter of time before something much worse happens.</p> Published on Citation Needed: "North Korea gets away with around $3 billion from Binance" - Molly White's activity feed 6ae3edd9b6faaacba7234df0 2026-10-30T01:07:37.000Z Molly White <article class="entry h-entry hentry"><header><div class="description">Published an issue of <a href="https://www.citationneeded.news/"><i>Citation Needed</i></a>: </div><h2 class="p-name"><a class="u-syndication" href="https://www.citationneeded.news/binance-theft" rel="syndication">North Korea gets away with around $3 billion from Binance </a></h2></header><div class="content e-content"><div class="media-wrapper"><a href="https://www.citationneeded.news/binance-theft"><img src="https://www.citationneeded.news/content/images/size/w2000/format/webp/2026/10/2022_-_Press_Conferences_BE6_1620_-52472404534-.jpg" alt="Changpeng Zhao speaking into a microphone, photographed from the side"/></a></div><div class="p-summary"><p>Stablecoin issuers froze about $2.4 billion of the roughly $6.3 billion stolen. The rest exceeds Binance’s insurance fund, and the man promising to make users whole isn’t supposed to be running the company.</p></div></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <a class="u-url" href="https://www.citationneeded.news/binance-theft"><time class="dt-published" datetime="2026-10-30T01:07:37+00:00" title="October 30, 2026 at 1:07 AM UTC">October 30, 2026 at 1:07 AM UTC</time>. </a></div><div class="social-links"> <span>Also posted to:</span><a class="social-link u-syndication mastodon" href="https://hachyderm.io/@molly0xfff/117526961419935070" title="Mastodon" rel="syndication">Mastodon</a><a class="social-link u-syndication bluesky" href="https://bsky.app/profile/molly.wiki/post/3mz2i32ld5c2s" title="Bluesky" rel="syndication">Bluesky</a></div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/feed/tag/binance" title="See all feed posts tagged "Binance"" rel="category tag">Binance</a>, <a class="tag p-category" href="https://www.mollywhite.net/feed/tag/crypto" title="See all feed posts tagged "crypto"" rel="category tag">crypto</a>.</div></div></footer></article> Note published on October 29, 2026 at 9:30 PM UTC - Molly White's activity feed 6ae3bb00b6faaacba7234da2 2026-10-29T21:30:40.000Z Molly White <article><div class="entry h-entry hentry"><header></header><div class="content e-content"><p>It looks like Binance is getting drained right now, across multiple hot wallets, for $2B and counting.</p><p>Pretty normal for exchanges to migrate wallets, NOT normal for them to then swap to Tether and dump</p><div class="media-wrapper"><a href="https://storage.mollywhite.net/micro/b1071895722c63802cd6_Screenshot-2026-10-29-at-5.28.15---PM.png" data-fslightbox=dfd9fa58b84999e77b30><img src="https://storage.mollywhite.net/micro/b1071895722c63802cd6_Screenshot-2026-10-29-at-5.28.15---PM.png" alt="Image" /></a></div></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp-block"><div class="timestamp">Posted: <a class="u-url" href="https://www.mollywhite.net/micro/entry/202610291725"><time class="dt-published" datetime="2026-10-29T21:30:40+00:00" title="October 29, 2026 at 9:30 PM UTC">October 29, 2026 at 9:30 PM UTC</time>. </a></div></div><div class="social-links"> <span> Also posted to: </span><a class="social-link u-syndication mastodon" href="https://hachyderm.io/@molly0xfff/117526327687628137" title="Mastodon" rel="syndication">Mastodon, </a><a class="social-link u-syndication bluesky" href="https://bsky.app/profile/molly.wiki/post/3mz27m5slcc2o" title="Bluesky" rel="syndication">Bluesky</a></div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/micro/tag/binance" title="See all micro posts tagged "Binance"" rel="category tag">Binance</a>. </div></div></footer></div></article> Putting music data to work - Posts feed https://www.coryd.dev/posts/2026/putting-music-data-to-work 2026-10-29T19:38:46.000Z Posts feed <div class="e-content block-subcanvas"><p>I had someone ask me the other day why I collect all the music data that I do and I wasn't sure how to answer. Some of it's an interest in my own listening patterns, and another part of it is nostalgia for the last.fm I used heavily during its heyday. I guess I like quantifying those things. It's become a bit more than that too — I curate artist bios, I pull in genre descriptions from Wikipedia, and I fiddle with metadata. I also put some of this data to work.</p> <p>I use <a href="https://www.navidrome.org">Navidrome</a> to listen to music. <a href="https://www.coryd.dev/posts/2025/i-made-a-music-app">I've written a client</a> and written at length about it. It's had plugin support for a little bit now and I have, of course, written a few. Since I have artist bios stored on my site for each artist, I wrote and exposed an API that returns those bios in HTML. I wrote a plugin for Navidrome that scans this endpoint periodically and pulls in those bios to display on artist views.</p> <p>I have art for every single album in Navidrome (mirrored to my site to scrobble against) that sits in a pull zone over at <a href="https://bunny.net/?ref=revw3mehej">bunny</a>. I wrote a macOS screensaver (you can still do this!) that queries an endpoint with all of the album cover URLs and mimics the iTunes/Apple Music album cover screensaver. <a href="https://www.coryd.dev/posts/2026/throwing-my-roku-in-the-trash">My Google TV</a> has a screensaver option that shuffles a Google Photos album. I have an automated job that pushes album art to a dedicated album as it's added.</p> <p>When I import an artist from Navidrome, the <a href="https://musicbrainz.org">MusicBrainz</a> ID is imported with it. I run a nightly job to query MusicBrainz for new releases from all of the artists in my collection. I've added a widget on the dashboard for my CMS that allows me to quickly scan these releases and dismiss or import them. If I import them, they're added to my <a href="https://www.coryd.dev/music/album-releases">anticipated albums page</a> and used to generate <a href="https://www.coryd.dev/music/releases.ics">an ICS file I subscribe to</a> so I can view them in my calendar.</p> <p>Recommendations are hard. The best ones are personal and sourced from fans. That's part of what made last.fm so compelling — the similar artists are derived from a trove of genuine listening data. <a href="https://github.com/NeptuneHub/AudioMuse-AI">AudioMuse-AI</a> does an eerily good job of generating similar artists (which I have available in Navidrome via the plugin for it) but can't offer novel recommendations. <a href="https://listenbrainz.org">ListenBrainz</a> has listening data (much like last.fm) and offers solid recommendations. I can query these recommendations using the MusicBrainz IDs I store (while filtering out artists in my library).</p> <p>I've built a separate concerts tracking app. It's a single page containing a table and it's populated by pulling the list of artists in Navidrome and comparing them to a query of the Ticketmaster API scoped to a 75-mile radius of the town I live in. I can hide concerts, buy tickets, or look up the venue.</p> <p>So, I suppose, I have a lot more than just vanity metrics. <a href="https://www.coryd.dev/music">But those are nice too.</a></p> </div> Fixing Illustrations on a Dark Background with CSS - Robb Knight • Posts • Atom Feed https://rknight.me/blog/fixing-illustrations-on-a-dark-background-with-css/ 2026-10-29T19:38:11.000Z Robb Knight <p>If you've visited my site recently you might have noticed some illustrations I've done appear on some pages, notably the home page and <a href="/404">my 404 page</a>. I wanted to use this brick drawing I did for <a href="https://rknight.me/notes/202610252020/">Inktober</a> but on the dark mode background is doesn't look good:</p> <figure><img src="https://cdn.rknight.me/site/2026/kombucha-girl-illustration-on-dark-and-light.jpg" alt="Two panels showing a woman. The first she is looking digsuted by the brick drawing on a dark background, the second she looks intrigued by it on a light background" /></figure> <p>My first thought was to just get rid of dark mode completely and just have light mode. I spoke to a handful of people about it and came to the conclusion that this was an extreme solution. Also, I like dark mode in general so it seems stupid to nuke it just for this.</p> <p>I tried a handful of different things like changing the line colour to white and just loading the correct version depending on the theme. This worked, but still looked shit on dark mode. I tried some other things like adding an outline or even a thicker line like a sticker might have but all of them had the same problem — I would need to make two versions of every drawing which I really didn't want to do.</p> <p>I had a vague recollection of being able to do a drop shadow on transparent PNGs and after some digging I found it can be done with <code>filter</code> and <code>drop-shadow</code>. Stacking two drop shadows give the best outline for what I wanted.</p> <pre class="language-css"><code class="language-css"><span class="token property">filter</span><span class="token punctuation">:</span> <span class="token function">drop-shadow</span><span class="token punctuation">(</span>0 0 1px #ececec<span class="token punctuation">)</span> <span class="token function">drop-shadow</span><span class="token punctuation">(</span>0 0 1px #ececec<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre> <p>It's not perfect but it does the job, especially on drawings that have a more defined outline like the hats.</p> <figure><img src="https://cdn.rknight.me/site/2026/illustrations-with-white-drop-shadow-filter.jpg" alt="A brick drawing and some hats with a white drop shadow on them both" /></figure> <p>Now I can start adding some more illustrations I've got lined up for the site.</p> 2026-10-29 14:56: Been having some fun with my 404 page. I love discovering little Easter eggs like... - Kev Quirk https://kevquirk.com/2026-10-29-1456 2026-10-29T14:56:00.000Z Kev Quirk <p>Been having some fun with my 404 page. I love discovering little Easter eggs like this on other people's sites. Just visit a random page, like <a href="https://kevquirk.com/mjkk">https://kevquirk.com/mjkk</a></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:19gy@qrk.one?subject=2026-10-29%2014%3A56">reply to this post by email</a>, or <a href="https://kevquirk.com/2026-10-29-1456#comments">leave a comment</a>.</p> </div> A whimsical CSS :target design for headings - James' Coffee Blog https://jamesg.blog/2026/10/29/whimsical-css-target-design-headings 2026-10-29T00:00:00.000Z James' Coffee Blog <style media="(prefers-color-scheme: dark)">pre { line-height: 125%; } td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #49483e } .highlight { background: #272822; color: #F8F8F2 } .highlight .c { color: #959077 } /* Comment */ .highlight .err { color: #ED007E; background-color: #1E0010 } /* Error */ .highlight .esc { color: #F8F8F2 } /* Escape */ .highlight .g { color: #F8F8F2 } /* Generic */ .highlight .k { color: #66D9EF } /* Keyword */ .highlight .l { color: #AE81FF } /* Literal */ .highlight .n { color: #F8F8F2 } /* Name */ .highlight .o { color: #FF4689 } /* Operator */ .highlight .x { color: #F8F8F2 } /* Other */ .highlight .p { color: #F8F8F2 } /* Punctuation */ .highlight .ch { color: #959077 } /* Comment.Hashbang */ .highlight .cm { color: #959077 } /* Comment.Multiline */ .highlight .cp { color: #959077 } /* Comment.Preproc */ .highlight .cpf { color: #959077 } /* Comment.PreprocFile */ .highlight .c1 { color: #959077 } /* Comment.Single */ .highlight .cs { color: #959077 } /* Comment.Special */ .highlight .gd { color: #FF4689 } /* Generic.Deleted */ .highlight .ge { color: #F8F8F2; font-style: italic } /* Generic.Emph */ .highlight .ges { color: #F8F8F2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #F8F8F2 } /* Generic.Error */ .highlight .gh { color: #F8F8F2 } /* Generic.Heading */ .highlight .gi { color: #A6E22E } /* Generic.Inserted */ .highlight .go { color: #66D9EF } /* Generic.Output */ .highlight .gp { color: #FF4689; font-weight: bold } /* Generic.Prompt */ .highlight .gs { color: #F8F8F2; font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #959077 } /* Generic.Subheading */ .highlight .gt { color: #F8F8F2 } /* Generic.Traceback */ .highlight .kc { color: #66D9EF } /* Keyword.Constant */ .highlight .kd { color: #66D9EF } /* Keyword.Declaration */ .highlight .kn { color: #FF4689 } /* Keyword.Namespace */ .highlight .kp { color: #66D9EF } /* Keyword.Pseudo */ .highlight .kr { color: #66D9EF } /* Keyword.Reserved */ .highlight .kt { color: #66D9EF } /* Keyword.Type */ .highlight .ld { color: #E6DB74 } /* Literal.Date */ .highlight .m { color: #AE81FF } /* Literal.Number */ .highlight .s { color: #E6DB74 } /* Literal.String */ .highlight .na { color: #A6E22E } /* Name.Attribute */ .highlight .nb { color: #F8F8F2 } /* Name.Builtin */ .highlight .nc { color: #A6E22E } /* Name.Class */ .highlight .no { color: #66D9EF } /* Name.Constant */ .highlight .nd { color: #A6E22E } /* Name.Decorator */ .highlight .ni { color: #F8F8F2 } /* Name.Entity */ .highlight .ne { color: #A6E22E } /* Name.Exception */ .highlight .nf { color: #A6E22E } /* Name.Function */ .highlight .nl { color: #F8F8F2 } /* Name.Label */ .highlight .nn { color: #F8F8F2 } /* Name.Namespace */ .highlight .nx { color: #A6E22E } /* Name.Other */ .highlight .py { color: #F8F8F2 } /* Name.Property */ .highlight .nt { color: #FF4689 } /* Name.Tag */ .highlight .nv { color: #F8F8F2 } /* Name.Variable */ .highlight .ow { color: #FF4689 } /* Operator.Word */ .highlight .pm { color: #F8F8F2 } /* Punctuation.Marker */ .highlight .w { color: #F8F8F2 } /* Text.Whitespace */ .highlight .mb { color: #AE81FF } /* Literal.Number.Bin */ .highlight .mf { color: #AE81FF } /* Literal.Number.Float */ .highlight .mh { color: #AE81FF } /* Literal.Number.Hex */ .highlight .mi { color: #AE81FF } /* Literal.Number.Integer */ .highlight .mo { color: #AE81FF } /* Literal.Number.Oct */ .highlight .sa { color: #E6DB74 } /* Literal.String.Affix */ .highlight .sb { color: #E6DB74 } /* Literal.String.Backtick */ .highlight .sc { color: #E6DB74 } /* Literal.String.Char */ .highlight .dl { color: #E6DB74 } /* Literal.String.Delimiter */ .highlight .sd { color: #E6DB74 } /* Literal.String.Doc */ .highlight .s2 { color: #E6DB74 } /* Literal.String.Double */ .highlight .se { color: #AE81FF } /* Literal.String.Escape */ .highlight .sh { color: #E6DB74 } /* Literal.String.Heredoc */ .highlight .si { color: #E6DB74 } /* Literal.String.Interpol */ .highlight .sx { color: #E6DB74 } /* Literal.String.Other */ .highlight .sr { color: #E6DB74 } /* Literal.String.Regex */ .highlight .s1 { color: #E6DB74 } /* Literal.String.Single */ .highlight .ss { color: #E6DB74 } /* Literal.String.Symbol */ .highlight .bp { color: #F8F8F2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #A6E22E } /* Name.Function.Magic */ .highlight .vc { color: #F8F8F2 } /* Name.Variable.Class */ .highlight .vg { color: #F8F8F2 } /* Name.Variable.Global */ .highlight .vi { color: #F8F8F2 } /* Name.Variable.Instance */ .highlight .vm { color: #F8F8F2 } /* Name.Variable.Magic */ .highlight .il { color: #AE81FF } /* Literal.Number.Integer.Long */ .highlight .nn, .highlight .n{color: light-dark(black, var(--dark-foreground-color)) }</style><style media="(prefers-color-scheme: light)">pre { line-height: 125%; } td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight { background: #f8f8f8; } .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ .highlight .err { border: 1px solid #F00 } /* Error */ .highlight .k { color: #008000; font-weight: bold } /* Keyword */ .highlight .o { color: #666 } /* Operator */ .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ .highlight .cp { color: #9C6500 } /* Comment.Preproc */ .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ .highlight .gd { color: #A00000 } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #E40000 } /* Generic.Error */ .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .highlight .gi { color: #008400 } /* Generic.Inserted */ .highlight .go { color: #717171 } /* Generic.Output */ .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ .highlight .gt { color: #04D } /* Generic.Traceback */ .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008000 } /* Keyword.Pseudo */ .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #B00040 } /* Keyword.Type */ .highlight .m { color: #666 } /* Literal.Number */ .highlight .s { color: #BA2121 } /* Literal.String */ .highlight .na { color: #687822 } /* Name.Attribute */ .highlight .nb { color: #008000 } /* Name.Builtin */ .highlight .nc { color: #00F; font-weight: bold } /* Name.Class */ .highlight .no { color: #800 } /* Name.Constant */ .highlight .nd { color: #A2F } /* Name.Decorator */ .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #00F } /* Name.Function */ .highlight .nl { color: #767600 } /* Name.Label */ .highlight .nn { color: #00F; font-weight: bold } /* Name.Namespace */ .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #19177C } /* Name.Variable */ .highlight .ow { color: #A2F; font-weight: bold } /* Operator.Word */ .highlight .w { color: #BBB } /* Text.Whitespace */ .highlight .mb { color: #666 } /* Literal.Number.Bin */ .highlight .mf { color: #666 } /* Literal.Number.Float */ .highlight .mh { color: #666 } /* Literal.Number.Hex */ .highlight .mi { color: #666 } /* Literal.Number.Integer */ .highlight .mo { color: #666 } /* Literal.Number.Oct */ .highlight .sa { color: #BA2121 } /* Literal.String.Affix */ .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ .highlight .sc { color: #BA2121 } /* Literal.String.Char */ .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ .highlight .s2 { color: #BA2121 } /* Literal.String.Double */ .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ .highlight .sx { color: #008000 } /* Literal.String.Other */ .highlight .sr { color: #A45A77 } /* Literal.String.Regex */ .highlight .s1 { color: #BA2121 } /* Literal.String.Single */ .highlight .ss { color: #19177C } /* Literal.String.Symbol */ .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #00F } /* Name.Function.Magic */ .highlight .vc { color: #19177C } /* Name.Variable.Class */ .highlight .vg { color: #19177C } /* Name.Variable.Global */ .highlight .vi { color: #19177C } /* Name.Variable.Instance */ .highlight .vm { color: #19177C } /* Name.Variable.Magic */ .highlight .il { color: #666 } /* Literal.Number.Integer.Long */</style> <style> @font-face { font-family: 'MonaspaceArgon'; src: url('/assets/fonts/MonaspaceArgon-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; } pre, code { font-family: 'MonaspaceArgon', ui-monospace, monospace; } </style> <p>The headings in my blog posts, and some pages, have HTML fragments so that each heading can be linked to. I seldom use this feature, most likely because, at present, I don't have a visual affordance to create such links. Occasionally, though, I find myself wanting to link directly to a heading, so I will make sure there is an anchor.</p> <p>One such occasion was yesterday, when I was adding a new section to my categories page that lists all of my “Advent” series of posts. I placed the Advent heading at the bottom of the page and added an ID so I could target it with a fragment link. <a href="https://jamesg.blog/categories#advent">See the Advent section</a>.</p> <p>By default, unless you see the <code>#advent</code> part in the URL, it was not immediately clear to the viewer to what part of the page I was linking, because the Advent section is at the bottom and the browser doesn't highlight the specific linked section. This encouraged me to make a more explicit highlight for headings. My site mascot now appears, rotated 15 degrees, next to a linked heading, to draw attention to that heading.</p> <p>Here is a screenshot of the feature:</p> <p><img alt='A subheading with the text "Advent" before which my mascot appears, rotated at a 15 degree angle toward the heading' src="https://jamesg.blog/assets/images/whimsicaldesigntarget.png?1"/></p> <p>And here is the code I used to implement the feature:</p> <div class="highlight"><pre><span></span><span class="nt">h2</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="nt">a</span><span class="o">)</span><span class="p">:</span><span class="nd">target</span><span class="p">::</span><span class="nd">before</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="k">content</span><span class="p">:</span><span class="w"> </span><span class="nb">url</span><span class="p">(</span><span class="s2">"https://jamesg.blog/assets/mascot/mascot.svg"</span><span class="p">);</span> <span class="w"> </span><span class="k">height</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="kt">rem</span><span class="p">;</span> <span class="w"> </span><span class="k">width</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="kt">rem</span><span class="p">;</span> <span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="kc">inline-block</span><span class="p">;</span> <span class="w"> </span><span class="k">margin-right</span><span class="p">:</span><span class="w"> </span><span class="mf">0.5</span><span class="kt">rem</span><span class="p">;</span> <span class="w"> </span><span class="k">rotate</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="kt">deg</span><span class="p">;</span> <span class="p">}</span> </pre></div> <p>The CSS selector applies to any <code>h2</code> that does not contain an <code>a</code> tag and where the <code>h2</code> is targeted using a HTML fragment. The selector uses the <code>::before</code> pseudo-element to add my site mascot.</p> <p>I got the idea at <a href="https://events.indieweb.org/2026/10/front-end-study-hall-061-saxhIC7ay0IT">Front End Study Hall today</a>. I had an earlier design where the heading would turn yellow and have a black background, but this, while drawing attention to the heading, was more explicit than required. Someone said the word “playful” and I immediately thought “maybe my site mascot could be used here!”</p> <script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a52461f72957a6b6',t:'MTc5MzMwMDAwMg=='};var l=window.parent.location,o;try{o=new URL(l.origin).origin}catch(e){try{o=new URL(new URL(l.href).origin).origin}catch(e){o=''}}var u='/cdn-cgi/challenge-platform/scripts/jsd/main.js?ray=a52461f72957a6b6',a=document.createElement('script');a.src=o?new URL(u,o).href:u;document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script> <a class="tag" href="https://events.indieweb.org/2026/10/front-end-study-hall-061-saxhIC7ay0IT">Front End Study Hall today</a> <a class="tag" href="https://jamesg.blog/categories#advent">See the Advent section</a> Caching, bot defense and a CDN - Posts feed https://www.coryd.dev/posts/2026/caching-bot-defense-and-a-cdn 2026-10-28T23:59:40.000Z Posts feed <div class="e-content block-subcanvas"><p>I've been wary of and interested in putting a CDN in front of my site. I had tools in place to <a href="https://www.coryd.dev/posts/2026/battling-bots">block bots</a> (<a href="https://www.coryd.dev/posts/2026/blocking-entire-countries-because-of-scrapers">and several countries</a>), but they were fragmented and it was an ongoing rock fight. I had a <a href="https://www.coryd.dev/posts/2026/my-router-is-not-a-calculator">Go job that banned IPs after too many 404s</a>, a crawler denylist that mirrored my robots.txt, and an SQL-injection probe filter (regex). I also wanted the improved load times and other niceties that come with a CDN. The catch (and cause for my concern) is that I wanted my existing Redis caching, live routes (like the now playing block on the home and music pages), and other bot-related mitigations to keep working.</p> <h1 id="setup">Setup</h1> <p>I've been using <a href="https://bunny.net/?ref=revw3mehej">bunny.net</a> to serve images here (and on <a href="https://follow.coryd.dev/@cory">my Mastodon instance</a>) for <em>ages</em>, so it was a natural shift to put their CDN in front of the site itself. I pointed the domain you're reading this on to a new pull zone, while leaving the apex and my admin pointing at the origin server. The "public" origin is accessible only via requests from the edge through bunny. Each request has a header set with a shared key, and Caddy rejects any requests to <code>www</code> without it. Anything live is excluded from edge caching: now playing, my contact form, and a few other APIs.</p> <h1 id="caching">Caching</h1> <p>I opted to have Go set cache lifetime per page with <code>Cache-Control</code> headers. There's a short default and longer ranges for pages that rarely change. I skipped bunny's Smart Cache (sometimes predictability is better than heuristics).</p> <p>Cache invalidation is handled using tags (much like I do with Redis): every response has a <code>CDN-Tag</code>; saving things in my admin is debounced for a few seconds and then purges the appropriate tag. The cache is also purged at startup.</p> <p>Redis caches database queries, bunny caches rendered HTML at the edge, and the page re-renders on every request that hits the origin.</p> <p>Database migrations run when the new server starts. They write to the database directly, don't invalidate tags (or go to jail or collect $100), and benefit from the startup check that dumps the public content cache.</p> <h1 id="blocking-things">Blocking things</h1> <p>The important part! (Sort of.) I ran <a href="https://bunny.net/docs/shield/waf">bunny's WAF</a> in learning mode and tuned rules. If you block things outright, you block things you shouldn't (e.g. don't block contact form submissions in English). I maintain the list of crawlers I block in my CMS: each agent is a string tied to a path, and my robots.txt is generated, in part, from that relationship. These are now also synced into the CDN's rule set to block the same crawlers at the edge. bunny also provides their own block lists, and one of those lists blocked folks on Tor and VPNs (oops—that's set to challenge now).</p> <h2 id="analytics">Analytics</h2> <p>My analytics are hand-rolled and minimal. I have country data displayed in a graph, and that was previously populated using a GeoIP lookup. bunny, conveniently, supplies a country header, and the analytics now use that. I tweaked the implementation to record visits on page load rather than exit (exit events don't fire as reliably). Crawlers get excluded altogether (yay blocking!).</p> <h2 id="reliability">Reliability</h2> <p>bunny has a feature called <a href="https://bunny.net/docs/cdn/performance/origin-shield#origin-shield">Origin Shield</a> that sets up an additional caching layer in front of my origin. Cache misses get consolidated into one point, and my origin server ends up seeing fewer requests. The added benefit (in addition to the performance) is that some of bunny's edge locations couldn't hit my origin (which is IPv4-only). Putting the shield behind an edge node that <em>can</em> reach the origin fixes that. The network topology is hostile and unknown and weird and unpredictable and magical.</p> <h2 id="breaking-things">Breaking things</h2> <p>Feed readers rely on <code>If-None-Match</code> to avoid redownloading unchanged feeds. I've left mine uncached so my (minimal) feed analytics can count polls. bunny drops conditional-request headers headed for the origin even for pass-throughs it doesn't cache, which means every poll is a 200. If I can't see the 304, I can't handle it properly, and, for that, I am appropriately apologetic.</p> <p>Request coalescing: this will break live routes. It's super handy for near-simultaneous requests for the same relatively static thing where a single copy can be returned in a performant fashion. This is antithetical to the notion of things that return unique and/or live responses. I put in an explicit skip list for those routes.</p> <p>When I deploy, visitors will briefly see 502s. A new copy of the Go binaries gets copied to the origin server, the app restarts, and Caddy hasn't reloaded its config yet (said config gets copied over as part of the deploy). There's now a short retry for Caddy to help mitigate this.</p> <p>For my now playing display: a page cached on the edge could flicker when it rendered older album art next to a live stream. Stale vs. live data: bad experience. The new cover is decoded off-screen and swapped into the view.</p> <h2 id="done-mostly">Done, mostly</h2> <p>Hand-maintained IP banning is gone, crawler lists are out of Caddy, GeoIP is gone, and most of that now lives at the edge. Oh, and I added an analytics chart of blocked bots. They've been fucking off more over time, which is nice. Things should be faster, too!</p> </div>