Shellsharks Blogroll - BlogFlock2026-07-10T00:04:27.788ZBlogFlockAdepts of 0xCC, destructured, fLaMEd, Aaron Parecki, Trail of Bits Blog, Westenberg, James' Coffee Blog, gynvael.coldwind//vx.log (pl), joelchrono, Evan Boehs, cool-as-heck, Kev Quirk, Posts feed, Sophie Koonin, <span>Songs</span> on the Security of Networks, cmdr-nova@internet:~$, Werd I/O, Johnny.Decimal, Robb Knight, Molly White, Hey, it's Jason!, Terence Eden’s BlogFinished reading Wasteland Warlords 3 - Molly White's activity feed6a4ff47491f30f1ebedf6e682026-07-09T19:20:20.000Z<article class="entry h-entry hentry"><header><div class="description">Finished reading: </div></header><div class="content e-content"><div class="book h-entry hentry"><a class="book-cover-link" href="https://www.mollywhite.net/reading/books?search=Wasteland%20Warlords%203"><img class="u-photo book-cover" src="https://m.media-amazon.com/images/S/compressed.photo.goodreads.com/books/1703146411i/202378461.jpg" alt="Cover image of Wasteland Warlords 3" style="max-width: 300px;"/></a><div class="book-details"><div class="top"><div class="title-and-byline"><div class="title"><i class="p-name">Wasteland Warlords 3</i> </div><div class="byline">by <span class="p-author h-card">James A. Hunter</span> and <span class="p-author h-card">Eden Hudson</span>. </div></div><div class="book-info">Published <time class="dt-published published" datetime="2024">2024</time>. 141 pages. </div></div><div class="bottom"><div class="reading-info"><div class="reading-dates"> Started <time class="dt-accessed accessed" datetime="2026-07-09">July 9, 2026</time>; completed July 9, 2026. </div></div></div></div></div><img src="https://www.mollywhite.net/assets/images/placeholder_social.png" alt="Illustration of Molly White sitting and typing on a laptop, on a purple background with 'Molly White' in white serif." style="display: none;"/></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <time class="dt-published" datetime="2026-07-09T19:20:20+00:00" title="July 9, 2026 at 7:20 PM UTC">July 9, 2026 at 7:20 PM UTC</time>. </div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=fantasy" title="See all books tagged "fantasy"" rel="category tag">fantasy</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=humor" title="See all books tagged "humor"" rel="category tag">humor</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=litrpg" title="See all books tagged "litRPG"" rel="category tag">litRPG</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=post_apocalyptic" title="See all books tagged "post-apocalyptic"" rel="category tag">post-apocalyptic</a>. </div></div></footer></article>Finished reading Wasteland Warlords 2 - Molly White's activity feed6a4ff43591f30f1ebedf6e2e2026-07-09T19:19:17.000Z<article class="entry h-entry hentry"><header><div class="description">Finished reading: </div></header><div class="content e-content"><div class="book h-entry hentry"><a class="book-cover-link" href="https://www.mollywhite.net/reading/books?search=Wasteland%20Warlords%202"><img class="u-photo book-cover" src="https://m.media-amazon.com/images/S/compressed.photo.goodreads.com/books/1700344924i/202378402.jpg" alt="Cover image of Wasteland Warlords 2" style="max-width: 300px;"/></a><div class="book-details"><div class="top"><div class="series-info"><i>Wasteland Warlords</i> series, book <span class="series-number">2</span>. </div><div class="title-and-byline"><div class="title"><i class="p-name">Wasteland Warlords 2</i> </div><div class="byline">by <span class="p-author h-card">James A. Hunter</span> and <span class="p-author h-card">Eden Hudson</span>. </div></div><div class="book-info">Published <time class="dt-published published" datetime="2023">2023</time>. 159 pages. </div></div><div class="bottom"><div class="reading-info"><div class="reading-dates"> Started <time class="dt-accessed accessed" datetime="2026-07-07">July 7, 2026</time>; completed July 8, 2026. </div></div></div></div></div><img src="https://www.mollywhite.net/assets/images/placeholder_social.png" alt="Illustration of Molly White sitting and typing on a laptop, on a purple background with 'Molly White' in white serif." style="display: none;"/></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <time class="dt-published" datetime="2026-07-09T19:19:17+00:00" title="July 9, 2026 at 7:19 PM UTC">July 9, 2026 at 7:19 PM UTC</time>. </div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=fantasy" title="See all books tagged "fantasy"" rel="category tag">fantasy</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=humor" title="See all books tagged "humor"" rel="category tag">humor</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=litrpg" title="See all books tagged "litRPG"" rel="category tag">litRPG</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=post_apocalyptic" title="See all books tagged "post-apocalyptic"" rel="category tag">post-apocalyptic</a>. </div></div></footer></article>Why are you always happy? - Joel's Log Fileshttps://joelchrono.xyz/blog/why-are-you-always-happy2026-07-09T16:00:00.000Z<p>Yesterday at work something very weird happened. During our lunch break, the conversation focused on me, at least for a couple minutes.</p>
<p>My group sat next to another coworker, she’s older in age than most of my group, from another generation that would often work more than the others unprompted and at the same time complain that she’s doing too much and nobody else does anything. At least that’s what my coworkers say about her when she’s not present, but I don’t really see a reason to share the critiques.</p>
<p>She’s rather friendly at lunch time and my group and hers get along well, even if they throw shade at her, they do that for pretty much everyone—I suspect every single group at work gossips about each other in the same way.</p>
<p>Today, she made a question directed at me, the title of this post, and people started to give answers and share their thoughts about me.</p>
<p>They said things about how I eat carelessly and don’t really gain much weight. I am a bit fat but it’s true that I don’t look it, though people who know me for a long time can see my body has gotten bulkier than in my early college years. They also said I’m young and naive, even though I’m quite aware of some things they are not, and just because I rarely talk, doesn’t mean I don’t listen or think about things.</p>
<p>Perhaps, they said, is that my first job has been very acomodating, that I didn’t have to fight as much as them to get where I am. I never had a job where I was heavily pressured into things or shouted at or with the usual Mexican work culture of getting overworked and underpaid, and of course, I am in no danger of losing my position anytime soon.</p>
<p>Eventually they made a few questions and realized that I am not married, and that I still live with my parents. That ended up becoming a joke and sort of a final answer to close the topic. And well, it’s true, I can use my money in a lot of ways that bring me joy, and not having to worry about rent or buying groceries is a huge plus.</p>
<p>Many of these things are true, and some are not so true, but neither reason is why I’m always “happy.”</p>
<p>By the way, all the shade and critiques and jokes like these are very common in my country, we call it <em>carrilla</em> and while it can get close to bullying, it’s actually playful and friendly, and doesn’t mean to hurt anyone. Mexicans can be very offensive and is hard to accept for a lot of people, just wanted to mention it in case anyone here feels like this is wrong, abusive or something.</p>
<p>During the discussion I did answer questions, I laughed at some ridiculous claims, I acknowledged how I hadn’t gone to the gym for ages and many other things. I participated, but I never actually answered why I am like this most of the time.</p>
<p>Honestly, it’s kind of a corny answer, and it’s also an incomplete one. There are many factors that have made me into who I am.</p>
<p>I kind of wanted to reply in a playful manner, give them <em>carrilla</em>, point out how they’d be happier too if they stopped complaining about everything and actually did something they were passionate about, besides drinking or partying when they are all five years older than me!</p>
<p>Again, <em>carrilla</em> is not something serious, they’d get it, I obviously lack knowledge about their lives and ignore a lot of things, but we would laugh which is what matters.</p>
<p>Though a part of me finds it true. I wish conversations didn’t revolve around work gossip and complains sometimes.</p>
<p>A topic of conversation that popped up was about the new generations, how we are stuck to our phones, how we have so many means of communication yet we remain silent and shy. It was an interesting observation, and I wondered why that is.</p>
<p>I can’t easily bring up what videogame I am playing at work, it is difficult for me to share which book I’m reading, and even if I mention a somewhat popular TV show or movie, these adults just don’t seem to be aware of what’s new! Or they’d ridicule me for doing that instead of adult things, I guess.</p>
<p>Like, seriously, I would love to chat about things, anything that I am passionate about. Or listen about anything they are passionate about, but nobody seems to do anything interesting, or at least nobody is interested in opening up and talk about it.</p>
<p>And even then, when I am almost always silent and rarely talk about me, they can tell how happy I am all the time.</p>
<p>Of course this isn’t true, I am not always happy, I get stressed out about many things, I worry about the future of the world, I care about my friends and people around me going through difficult times, many losses have been had this year than I ever expected. I am sad when people get into dumb arguments online, I have cried because of moments like that before.</p>
<p>I’m human going through life and wants people to get along with. I guess focusing on different things, trying to see them through different angles. I also write, and that really is great, even if I can get a bit smug because of it. I’m not better than them, or superior in anyway due to this mindset.</p>
<p>I don’t know, it’s not just videogames or books, which I enjoy don’t get me wrong. I have true friendships, online, and in person. I have a hope that things will get better. I am content with what I have, and I have faith, which sustains me through it all.</p>
<p>I am curious, what is the impression you cause on other people? Are you also a cheerful person? or are you often seen as a grumpy one? It’s funny because I always thought I’d seem grumpy and serious, but I guess I’m just happy during lunch time because I get to eat!</p>
<p>In any case, it’s more than being single and living with my parents—but I can’t deny that helps a lot too.</p>
<p>This is day 94 of <a href="https://100daystooffload.com">#100DaysToOffload</a></p>
<p>
<a href="mailto:me@joelchrono.xyz?subject=Why are you always happy?">Reply to this post via email</a> |
<a href="https://fosstodon.org/@joel/116890886089318112">Reply on Fediverse</a>
</p>As social networks fill up with AI slop, trusted relationships and communities will win. - Werd I/O6a4fc47f9a650a00018aefd22026-07-09T15:55:43.000Z<p>Link: <a href="https://www.pangram.com/blog/ai-in-your-feed"><em>AI Content Is Everywhere on Social Media, Especially LinkedIn, by Max Spero at Pangram</em></a></p><p>This is one of the core effects of AI: even when people are not engaging with AI-generated content directly, it’s hard to avoid. Our feeds are increasingly full of AI slop.</p><blockquote>“AI-generated content appeared across all social media platforms in our data set. The average AI rate across all scanned items was 13.8%, but specific rates varied by platform and item length. On four out of five platforms, longer content was more likely to be AI-generated than shortform content. Across all platforms, one in four longform items (25.72% of items over 250 words) were fully AI-generated.”</blockquote><p>Specifically, long-form content on LinkedIn was 41% likely to be AI-generated, which shouldn’t surprise anyone who’s browsed LinkedIn lately. Medium was 31% likely and X was 29% likely. Open social web platforms like Bluesky and Mastodon don’t seem to have been a part of the dataset, but I think it would be foolish to assume they’re immune.</p><p>Some caveats here: the analysis was done by Pangram, which builds a browser extension and back-end tech that attempts to detect AI-generated content. That’s an imperfect process, and there are no tools that are completely reliable at making this distinction. False positives and false negatives have been common with these tools, although <a href="https://www.pangram.com/blog/all-about-false-positives-in-ai-detectors">Pangram claims a 0.01% false positive rate</a>. So take it with a pinch of salt, but it’s reasonable to assume that these numbers are <em>directionally</em> true.</p><p>All of this serves to drive trust in these platforms even lower. Increasingly, people on platforms like LinkedIn are being lazy writers and using AI to produce content that you don’t want to put the effort into. I generally think that if you can’t be bothered to write something, it’s not reasonable to ask people to read it; still, there may be some value in AI <em>assisted</em> writing, depending on the piece and how it was produced. (That kind of AI content, by the way, was not really measured by this test.) But AI has also led to a lot of outright spam making its way into people’s feeds in order to shamelessly build clout and advertising revenue.</p><p>Both things are making these platforms unusable, which in turn is driving people to smaller communities and group chats with people they <em>know</em> they can trust. I believe that’s going to be a big trend: AI leading to a noticeable drop in quality that drives people away from the platforms where it’s allowed to thrive. In that world, platforms that foster trusted relationships and communities will win.</p><p><em>Via </em><a href="https://www.404media.co/linkedin-and-x-are-flooded-with-ai-spam-browsing-data-suggests/"><em>404 Media, which has characteristically great coverage of the story</em></a><em>.</em></p>IndieWeb Fiction Carnival: May 2026 Roundup - Werd I/O6a4faab69a650a00018aefb42026-07-09T14:15:13.000Z<img src="https://images.unsplash.com/photo-1604018229934-2f5f1c8edf16?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDJ8fHN0aWNrc3xlbnwwfHx8fDE3ODM2MDY0OTN8MA&ixlib=rb-4.1.0&q=80&w=2000" alt="IndieWeb Fiction Carnival: May 2026 Roundup"><p>Back in May, I signed up to host the IndieWeb Fiction Carnival, and kicked it off with a prompt: <a href="https://werd.io/indieweb-fiction-carnival-may-2026/" rel="noreferrer"><em>sticks and stones will break my bones</em></a><em>.</em></p><p>I'm incredibly late with my roundup: just as soon as I'd kicked it off, life became chaotic in a way that won't settle down until September. Which is a poor excuse, because I received some great submissions.</p><p><a href="https://daniel.industries/2026/05/09/pull/?ref=werd.io" rel="noreferrer">Daniel Miller wrote <em>Pull</em>:</a></p><blockquote>The first chamber was larger than the second. Wren heard and felt the pneumatic doors close behind them and was careful to place one foot next to the other, in a stable stance, and took hold of the handrails. They felt their boots lock onto the walkway. The loud, mechanical horn blared its single warning and clouds of thin white mist filled the room. Wren stared straight ahead but could see in the peripheral vision possible through their helmet’s visor the particles cling to their suit. In seconds they covered the visor as well.</blockquote><p><a href="https://zacharykai.net/notes/tear?ref=werd.io" rel="noreferrer">Zachary Kai wrote <em>Tear Me Down, Build Me Back Up</em></a>:</p><blockquote>They repeated the usual version of this phrase, turned on him in the second person, until it became so pervasive they might've well have tattooed it on the insides of his eyelids.</blockquote><p><a href="https://aprilscable.neocities.org/posts/larasneighbour?ref=werd.io" rel="noreferrer">April wrote <em>Lara's Neighbour</em></a>:</p><blockquote>Being a young lady in the neighborhood. One of the elderly man came around one day towards Lara and asked when is she getting hitched? Flabbergasted by his question - she said she won't be getting married and then this oldie guy got on her nerves by saying that a young lady is a BURDEN on the family and getting married removes that burden.</blockquote>
<!--kg-card-begin: html-->
<p><em>Also syndicated to <a href="https://news.indieweb.org/en?ref=werd.io" class="u-syndication">IndieNews</a>.</em></p>
<!--kg-card-end: html-->75 reasons to start a personal website - James' Coffee Bloghttps://jamesg.blog/2026/07/09/75-reasons-to-start-a-personal-website2026-07-09T00:00:00.000Z
<p>I love having a personal website. Here, I share reflections, stories, thoughts, ideas, and more. Because I have a website, I always have the idea in the back of my mind that there is a place for my writing. I can write a story and share it with friends, and even the world. What I write might not be perfect, but it is mine. This is my home for my creative works.</p><p>Earlier today, I read <a href="https://kaia.starscene.com/indexnew.html">Kaia</a> make an argument for having a personal website that really struck a chord with me:</p><blockquote>so this manifesto isnt overly long to just go tell you to make a site in defiance of social media or anything like that (although thats a valid reason). i want to encourage you to be creative</blockquote><p>I love the idea of defining websites in terms of what they can do, rather than in opposition to what exists. This got me thinking: maybe I should make a list of reasons why someone might want to start a personal website? And so I went to my whiteboard and started jotting down ideas. Before I knew it I had 10, 20, 30 reasons why someone may want to start a personal website.</p><p>This post exists in large part because someone half-way across the world wrote a blog post and a friend shared it in a community I’m in. I think this illustrates the potential of the web: we can advance and build on each other’s ideas.</p><p>With that in mind, here are 75 reasons why you might want to start a personal website. There are likely many more, but here are the ones that came to mind for me.</p><ol><li>Your site can be a creative playground for whatever kind of art you do, or want to do. Want to write? Start writing a few things down and see if blogging is right for you. Love design? Draw your dream site on paper and see if you can make it on the web.</li><li>With your website, you can showcase what you are proud of: essays, poetry, illustrations, music, recipes – anything you have made, you can share it on your website.</li><li>What you share on your website – whether it’s a personal reflection, a set of instructions on how to do something, or something else entirely – might help someone.</li><li>What you share on your website might inspire someone (like Kaia did for me!).</li><li>Once you have a site, there are so many skills you can learn if you are interested: web design, HTML, CSS, and JavaScript, information architecture, and more. I am still learning new things about all of these areas despite this website now being six years old.</li><li>The skills you learn while making a website will last you a life-time. Even if you stop making web pages, what you learn about layout, design, and whatever you decide to do with your site can stick with you.</li><li>You can participate in a community of people who have personal websites. The <a href="https://32bit.cafe/" rel="noreferrer">32-Bit Cafe</a>, the <a href="https://indieweb.org" rel="noreferrer">IndieWeb</a>, the <a href="https://forum.melonland.net/" rel="noreferrer">MelonLand Forum</a>, <a href="https://bearblog.dev/discover" rel="noreferrer">Bear Blog</a>, <a href="https://omg.lol" rel="noreferrer">omg.lol</a>, <a href="https://neocities.org" rel="noreferrer">Neocities</a>, and so many other spaces exist for people who have personal websites to connect. Indeed, you’re not alone: there are countless people out there making websites.</li><li>You can participate in a blogging carnival if writing is your thing. This is when a rotating host chooses a topic and everyone interested writes about it on their website. The IndieWeb Carnival is a good place to start, but there have been carnivals on everything from books to mathematics. And you could even start your own, too.</li><li>On your website, you control the design. You can make your site look the way you want! You can experiment with different typefaces, imagery, and more.</li><li>On your site, you control the layout. You can present and arrange things however you want!</li><li>You can use whatever colours you want on your website.</li><li>You can experiment with animation on your website.</li><li>You can write as much or as little as you would like – indeed, you can do what you want on your website! There are no character limits, and you can control how your writing is displayed. I have designed my site for reading my words, for example, because I love sharing words on the web.</li><li>When you have a website, you have a space you know you can go to create and share what you have made with the world.</li><li>You can share your website with friends so they can catch up on what is new in your world.</li><li>You have more control over your website than you do on social media. And if you choose a tool for hosting a website that supports data export (or if you decide to make your own website by hand with code), you will be able to export your data from your website at any time. You own your data.</li><li>You can create on your own terms. You don’t have to be surrounded by algorithms on your website.</li><li>The indie web community knows that <a href="https://indieweb.org/life_happens">life happens</a>. You can let your website sit for a while if you want or need to, and come back to it whenever you are ready.</li><li>By having a website, you can be the change you want to see in the web.</li><li>You can start conversations about topics that interest you.</li><li>You can participate in conversations others have started.</li><li>You can help build the personal website community. There are already meet-ups happening all around the world for people who make websites (there is even a <a href="https://2026.html.energy/">HTML Day</a> which, in 2026, will have events in everywhere from Cologne to Dallas to Saskatoon to Kuala Lumpur).</li><li>The skills you build making a personal website may be useful for making other kinds of websites (i.e. a site that advocates for a cause you care about).</li><li>As you create on your website, you will build an archive of your work. Over time, you’ll be able to look back and see yourself grow.</li><li>Over time, you can change the design of your website so that it fits you as you grow.</li><li>You can blog with friends!</li><li>You can make web pages about all of your interests: music, film, books, games.</li><li>You can share moments that bring you joy.</li><li>You can connect with other people who share similar interests. You might even make friends, too.</li><li>You can be as playful as you want on your website. Your website could have a whimsical design, be a place where you share things that made you laugh, have a fun mascot – whatever you want.</li><li>You can see what is possible with the web.</li><li>You become part of the history of the web: you’ll join the community of people who have made personal websites to express themselves online.</li><li>You can post into the void if you would like (either anonymously, or on your own website).</li><li>You can create a professional presence on the web if that interests you (i.e. you can create a portfolio on your website, and/or share your resume).</li><li>You might meet people with whom you can start a group blog.</li><li>You can experiment with a different way of interacting with technology, one where you have more control and there is less pressure to create in a certain way.</li><li>Your website can do whatever you want it to do. Your website can be what you want it to be. Want your website to be closed on Mondays? You can do that. Want to add a guestbook so people who have seen your website can leave you a note? You can do that, too. You can do things your own way on the web.</li><li>You can curate lists of all the interesting things you have found on the web and share them.</li><li>You can ask questions in blog posts without knowing the answers; maybe you’ll start a discussion.</li><li>Your website never has to be finished: you can build and add to it whenever you have time, whether that means every day, every month, or every year.</li><li>Over time, you will build an archive of pages and works that you can consult as you create new things.</li><li>Whenever someone asks how to connect with you, you can share your personal website!</li><li>You can advocate for civic causes on your personal website.</li><li>You can build a presence on the web that can outlast social networks, so long as you keep your site online.</li><li>You can build a home on the web.</li><li>As you explore the web, you might start to ask yourself “how did they make that?” when you see a cool feature on a website.</li><li>When you have a website, you might start to realise you want technology to be a different way, and have experience to help you articulate how you want things to be.</li><li>You can start a digital garden to organise your thoughts on topics that interest you.</li><li>The potential of personal websites is so great that there are plenty of opportunities to make new things. What people have made before can serve as an example, but as a website owner you get to choose what you make. You can be as creative as you want to be on your website.</li><li>You can keep all of your creative works – drawings, poems, videos, stories – in a single place.</li><li>You can create a single page that links out to other places people can find you on the web.</li><li>As you experiment on your website, you might find you really like doing something (i.e. using a specific design technique, writing in a certain way) and feel inspired to create more.</li><li>You can show to all of your friends that the web can be a different way.</li><li>You can experiment with your creative process.</li><li>You can write guides on how to do things so that: (i) future you remembers how to do the thing, and; (ii) so that others can learn from you. I especially love doing this when there is no guide on the web on how to do something, or if the existing guides are too complex.</li><li>You can create as many placeholders as you want while you think about what you want to make; your site doesn’t need to be polished from day one.</li><li>You can publish photographs in their full quality without having to think about how they fit into a standard grid.</li><li>You can decide how to organise all of your creative works. What about creating a web page that contains a story you wrote, with an accompanying soundtrack you made? That’s possible with the web!</li><li>You can make a web page with lots of useful links you have found so that you can access those links across different devices, and so that your friends can see them, too.</li><li>You can create URLs (links) to all the ideas you are passionate about so other people can reference them in their works, and so that you can easily find your ideas, too.</li><li>You can share reading lists for subjects you are interested in.</li><li>Over time, you will learn that you don’t need to be a technical expert to build a website: the web is for everyone.</li><li>Your website will be accessible from wherever someone has an internet connection. People will not need to have an account with a proprietary service to see your creative works. (If you post on Instagram, I can’t see it because I don’t use Instagram. But if you share your creativity on the web, I can see it because it’s on the web!)</li><li>You can brainstorm new ideas for your personal website with your friends; making websites can be a personal creative act, but also a collaborative one, too.</li><li>You can make as many or as few pages as you want: the only limits are your imagination.</li><li>You can share your creativity with the web without worrying about pop up banners that a platform adds.</li><li>You can share your website with as many or as few people as you would like.</li><li>You can take pride in building something that you use.</li><li>Your website might inspire someone else to make their own website.</li><li>The web is more fun when everyone is doing their own thing.</li><li>You can create for the sake of creating, and/or because you want to make things to share with friends. You don’t need to have another reason to put something on the web.</li><li>The web is open and free and decentralised. By publishing on the web, you can demonstrate the power of these values.</li><li>You can be yourself.</li><li>Making websites is fun!</li></ol><p>Wait… that’s only 74 reasons? Yes, I have a habit of cutting myself short in these lists. If you have a personal website, I encourage you to reflect on, and, if you would like, share, the reason(s) that you think someone should start a personal website. You may already have written about this before, but I think the web is special enough that it is worth us continually asking ourselves what potential this medium has for both ourselves and others.</p><p>Need even more reasons? The <a href="https://indieweb.org/why" rel="noreferrer">IndieWeb wiki has been gathering reasons to start a website</a> for a while, too.</p><p>The web isn’t perfect: some things are still hard to do. And the web community hasn't worked everything out yet: not everyone wants to post in public, but yet publishing privately or to only a group of friends on the web is hard. </p><p>Starting a website isn’t for everyone, either: you might not want to start a website, and that is okay, too. Readers make up the web just as much as those who publish. It’s better to enjoy reading the web than to feel pressured into starting a website when you’re not ready.</p><p>With that said, I hope the list above has inspired you in some way. If you already have a personal website, you might have come away with a new perspective. If you were thinking about starting one, you might have seen a reason to start one that resonates with you. If a friend sent you this to encourage you to start a website, maybe now you see why they talk so much about websites.</p><p>You don’t need to know how to code to make a website: tools like <a href="https://omg.lol/">omg.lol</a>, <a href="https://bearblog.dev/">Bear Blog</a>, and more all exist to help you start a website. That is to say, don’t be deterred because you think you need to have technical skills to make a website. The web is for everyone. I love the web because it is for everyone.</p><p>Do you feel motivated to start a website now? Great! If you need guidance on where to begin, I have a page with some links that relate to <a href="https://jamesg.blog/make-a-website">making your own website</a>. Need inspiration on what to make? I have a list of <a href="https://jamesg.blog/2024/02/19/personal-website-ideas">100 things to do on your personal website</a>, and a list of <a href="https://jamesg.blog/2024/03/10/100-more-personal-website-ideas">100 more ideas</a>, too.</p><p>Now, go create something on the web! Have fun, be yourself, and experiment. Maybe you’ll turn around six years from now and look back thinking how glad you were to start a website, just as I am now.</p>
<!--kg-card-begin: html-->
<p><a class="u-syndication" href="https://news.indieweb.org/en">Also posted on IndieNews</a>.</p>
<!--kg-card-end: html--><script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a18663f57cabf09d',t:'MTc4MzU5MDI3MA=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';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://2026.html.energy/">HTML Day</a>
<a class="tag" href="https://32bit.cafe/">32-Bit Cafe</a>
<a class="tag" href="https://bearblog.dev/">Bear Blog</a>
<a class="tag" href="https://bearblog.dev/discover">Bear Blog</a>
<a class="tag" href="https://forum.melonland.net/">MelonLand Forum</a>
<a class="tag" href="https://indieweb.org/life_happens">life happens</a>
<a class="tag" href="https://indieweb.org/why">IndieWeb wiki has been gathering reasons to start a website</a>
<a class="tag" href="https://jamesg.blog/2024/02/19/personal-website-ideas">100 things to do on your personal website</a>
<a class="tag" href="https://jamesg.blog/2024/03/10/100-more-personal-website-ideas">100 more ideas</a>
<a class="tag" href="https://jamesg.blog/make-a-website">making your own website</a>
<a class="tag" href="https://kaia.starscene.com/indexnew.html">Kaia</a>
<a class="tag" href="https://neocities.org">Neocities</a>
<a class="tag" href="https://news.indieweb.org/en">Also posted on IndieNews</a>
<a class="tag" href="https://omg.lol">omg.lol</a>
<a class="tag" href="https://omg.lol/">omg.lol</a>
RE: Screens ≠ Books - Joel's Log Fileshttps://joelchrono.xyz/blog/re-screens-books2026-07-08T21:45:00.000Z<p>Since <a href="https://mas.to/@janerationx">JanerationX</a> started a new blog on <a href="https://pika.page/">Pika</a> a couple months ago, I have been enamoured by it. She is not afraid to express her thoughts and is refreshing to see.</p>
<p>I’ve been meaning to add her to my blogroll because of how cool she is, and I have wanted to comment on some of the posts, such as the one on <a href="https://janerationx.me/posts/the-human-touch/">the human houch</a>, or another one about how <a href="https://janerationx.me/posts/yeah-social-media-is-dead">social media is dead</a>. So yeah, go read those! Can’t help but appreciate how raw her writing is and how unapologetic her opinions are.</p>
<p>To continue contributing to <a href="https://robertbirming.com/julyreply/">July Reply</a>, I thought that <a href="https://janerationx.me/posts/screens-books">this latest post</a> would make for a nice reply from me. I’ll be trying to speak my mind about things as well in something that I love: Reading books, ereaders, and analog things!</p>
<p>First, it is absolutely true that the feeling of a book is a wonderful pleasure. A book that is well loved, or a book that is brand new, each has its charms and traits, and no piece of technology will ever equate to the analog sensation it provides.</p>
<p>After all, there’s a reason why I have a growing interest on writing by hand or listening to music offline, and I often still buy at least one physical book every couple of months.</p>
<p>The one thing that kind of irked me about the post, is not that books aren’t great, but that the screens of an e-reader and the screen of any other device are <em>extremely</em> different, and much less damaging than your average IPS/LED screen.</p>
<p>I felt like there were a few misconceptions, and I wanted to gently correct them, if I may do so in this little corner of the web I call my blog, I’m sorry, I couldn’t help myself, I had to share some good news!</p>
<p>First, e-ink screens do not need a backlight to function! I am unable to explain how the technology actually works, but it’s pretty much just a panel that prints information on itself and displays it in the same way a sheet of paper would. Think of it like an improved version of a calculator or a cheap digital watch display, they don’t really have a light—other than an LED in the corner that you can turn on for a second to see the time—that’s why the battery lasts so long!</p>
<p>Most ereaders do come with a backlight of course, but it’s just a useful bonus feature, and only really needed at night, otherwise, an e-ink screen can be lit up by any external light source just like a sheet of paper in a book needs light to be seen.</p>
<p>Also, when you do use the backlight, most have a blue light filter setting to avoid eye strain. Another funny thing is that you don’t need power to keep e-ink screens working, it can display the same thing indefinitely, you just need energy to change its state.</p>
<p>Of course, there’s other points and negatives to Kindles. Such as a false sense of ownership, with Amazon messing up and even modifying purchased ebooks from people without consent, altering personal libraries or even banning users, unable to access books they paid for!</p>
<p>However, it is also true that you can acquire digital books without any DRM, books which you can put in a hard drive or USB or any medium you personally own, and transfer to your device without a problem!</p>
<p>Physical books should always have a place, and it’s a shame to see some publishers cheapening out as they prefer to earn more selling on digital form, with proprietary platforms more often than not.</p>
<p>I guess I just wanted to say that e-ink screens and book pages have a lot more in common than one may think. As do digital and physical copies, as long as they can be owned by the individuals, or why not, through libraries thanks to services like Libby or Overdrive!</p>
<p>The real enemy is being unable to access the books you own, just because of the greed of some companies who don’t respect what should be our rights as a costumer. I think digital and physical ownership are of equal value, and books (or any media) you buy should belong to the person who paid for it!</p>
<p>In the end, screens aren’t equal to books, but e-ink isn’t too bad I’d say :3</p>
<p>This is day 92 of <a href="https://100daystooffload.com">#100DaysToOffload</a>.</p>
<p>
<a href="mailto:me@joelchrono.xyz?subject=RE: Screens ≠ Books">Reply to this post via email</a> |
<a href="https://fosstodon.org/@joel/116886574230674361">Reply on Fediverse</a>
</p>Startups track business metrics. Newsrooms should learn from them. - Werd I/O6a4e57db19899d00015d87f12026-07-08T13:59:55.000Z<p>Link: <a href="https://news.crunchbase.com/saas/metrics-unit-economics-questions-sagie/?ref=werd.io"><em>Your SaaS Metrics Are A Result, Not A Strategy, by Itay Sagie in Crunchbase News</em></a></p><p>I still subscribe to sites like Crunchbase News from my time in startup-land; although it’s been a while since I’ve run the financial side of a business, I’m interested, and I know that I’ll run one again. I see stories like this and wonder: what would it look like for a newsroom to think this way? In startups, these metrics are known top to bottom, but I’ve rarely heard business teams talk about <a href="https://executiveeducation.wharton.upenn.edu/thought-leadership/wharton-online-insights/why-customer-lifetime-value-matters/?ref=werd.io">LTV</a> (customer Life Time Value), <a href="https://www.paddle.com/resources/customer-acquisition-cost?ref=werd.io">CAC</a> (Customer Acquisition Cost), or even <a href="https://www.salesforce.com/sales/revenue-lifecycle-management/annual-recurring-revenue-arr/?ref=werd.io">ARR</a> (Annual Recurring Revenue). </p><p>This may be happening in finance and fundraising teams, but the culture of talking about customers / donors in teams more widely often simply isn’t there: metrics aren't communicated, dashboards aren't made available, the concepts of the metrics themselves are not explained. Not everyone should be thinking about this all the time – the firewall between business and editorial is important to maintain – but in order to make sharp prioritization and experimentation decisions, the business side should be much more customer / donor focused than they often are.</p><p>Beyond that, this piece points out, rightly, that metrics are not strategy: they’re the measurable outcome of your strategy. They’re important tools to help you figure out cause and effect and improve your revenue efficiency, but they are not the underlying mechanism.</p><p>Interesting provocation here from the author:</p><blockquote>“The Rule of 4 adds a simple durability check: ARR growth divided by annual customer churn should be above four. If it is low, growth may be hiding a leaking bucket.<br><br>[The board should ask:] are we growing on top of a loyal customer base, or replacing customers we should have kept?”</blockquote><p>Growth in annual recurring revenue — the portion of your revenue that is from recurring customers like subscribers or monthly / annual donors — is expressed as a percentage. So is churn: what percentage of customers (paid subscribers, members, recurring donors) cancel their commitments and don’t return?</p><p>How many newsrooms have those numbers handy? What would it take to measure them? Which systems are missing that would let you do that?</p><p>There is <em>so much</em> that newsrooms — including non-profit publications — can learn from for-profit startups and other businesses. There’s a lot to be gained by sharing knowledge from those other domains. Figuring out which metrics successful businesses track and mapping the data gaps inside a newsroom is a good place to start.</p>A bug which only affected left-handed users - Terence Eden’s Bloghttps://shkspr.mobi/blog/?p=724972026-07-08T11:34:43.000Z<blockquote><p>Verily, some of our brethren (and sistren) be afflicted with a sinister disposition. While the righteous scroll using the thumb of their right hand - as is good and proper - an accurs'd minority swing the other way.</p></blockquote>
<p>Look, you try writing an interesting bug report without sounding like a clanker, OK!</p>
<p>I try to optimise my blog as much as possible. It may not look like much, but it has got it where it counts. I've made a lot of special modifications myself to the base WordPress install.</p>
<p>One of those modifications is reducing the amount of JavaScript in use to the bare minimum. Everything functions without it, but there are a few places where it helps - the most notable being comments.</p>
<p>That's why I was distressed when a loyal reader wrote in saying there was a bug on my site. When they were scrolling the page a comment box would suddenly appear and interrupt their browsing.</p>
<p>I scroll my own site a lot (probably more than is healthy) so why hadn't I noticed this bug?</p>
<p>Because I scroll with my right thumb and the bug reporter uses their left. The "reply" link which was being triggered is on the left side of the page. A bug which won't be triggered by righteous people but infuriating to those who will surely be left behind after The Rapture™.</p>
<p>To be fair, <a href="https://core.trac.wordpress.org/ticket/46713">this bug was reported seven years ago</a> - but I guess the WordPress team have been too busy cleaning up after their mad God-Emperor to take a look at it.</p>
<p>Back in 2017, a developer <a href="https://github.com/WordPress/wordpress-develop/commit/14dd35e62e1325ca1c6caef0a8623ce3f02d7da9">added a <code>touchstart</code> listener to link clicks</a>. I don't really understand why. At one point in history, browsers couldn't be sure if a touch event was the start of a <code>click</code> or a double-tap to zoom. So firing an even when a touch occurred on a link sort of made sense to avoid a 300ms delay.</p>
<p>But that hadn't been the case for several years - <a href="https://developer.chrome.com/blog/300ms-tap-delay-gone-away">as this 2013 blog post makes clear</a>. Even in 2015 <a href="https://github.com/ftlabs/fastclick">it was no longer an issue</a>.</p>
<p>So why was this lefty-baiting code added? Not a clue.</p>
<p>Anyway, <strong>seven years</strong> after the bug was reported <a href="https://github.com/WordPress/wordpress-develop/pull/12168">I committed a fix</a>. It isn't the most sophisticated change to WordPress - merely deleting a couple of lines. But hopefully it will stop those strange and unusual mutants from complaining that their unnatural thumb-usage is accidentally triggering unwanted events on my website.</p>
<p>Sadly, there is as yet no way to prevent the corrupt from using our blessed sites. The WHAT-WG haven't seen fit to take on board my suggestion of <code><meta handed="right"></code> to keep out the unwanted and polluted. So, hopefully, this change will at least prevent them complaining.</p>
<p>Why, yes officer, I have had a glass or two of tonic wine. Why do you ask?</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=72497&HTTP_REFERER=Atom" alt width="1" height="1" loading="eager">Mutation testing comes to DAML - Trail of Bits Bloghttps://blog.trailofbits.com/2026/07/08/mutation-testing-comes-to-daml/2026-07-08T11:00:00.000Z<p>In April we released <a href="https://blog.trailofbits.com/2026/04/01/mutation-testing-for-the-agentic-era/">Mewt</a>, our open-source mutation-testing engine that finds the gaps in your test suite. Today we’re expanding it with support for DAML, the language Canton Network applications are written in. Mewt now reads DAML, generates several classes of mutants (including two built for DAML&rsquo;s authorization primitives), and runs them through your existing test suite to count how many mutants survive. If you want to try it, simply install Mewt from the <a href="https://github.com/trailofbits/mewt">repository</a>, point a <code>mewt.toml</code> at your project and its test command, and use <code>mewt run</code>.</p>
<p>For a team shipping DAML to production, that count is what a passing test run is actually worth: it puts a number on how much your suite checks, whereas a green run on its own does not.</p>
<h2 id="why-damls-coverage-reports-lie">Why DAML’s coverage reports lie</h2>
<p>Test coverage is the most reassuring lie in smart-contract development. Hitting 100% line coverage tells you the test runner walked the code; it does not tell you whether any test would fail if that code stopped doing what it is supposed to. We have been grading test harnesses by how many mutants they kill since at least <a href="https://blog.trailofbits.com/2019/01/23/fuzzing-an-api-with-deepstate-part-2/">2019</a>, and <a href="https://blog.trailofbits.com/2025/09/18/use-mutation-testing-to-find-the-bugs-your-tests-dont-catch/">our primer on finding the bugs your tests don&rsquo;t catch</a> shows how a green suite can still miss the bug that matters.</p>
<p>DAML&rsquo;s built-in coverage measures execution at the template and choice level: which templates were created and which choices were exercised over the test run. It reports whether each choice was exercised, not what happened inside it. A test that exercises a choice once and asserts nothing about the result reports that choice as covered. The report prints the same green percentage whether the test verifies the outcome or discards it.</p>
<h2 id="how-mutation-testing-works">How mutation testing works</h2>
<p>Instead of asking whether your tests reached the code, mutation testing grades your tests by sabotaging that code. The engine generates mutants, copies of the code that each carry one small deliberate change: a flipped comparison, a removed branch, a dropped party. It then runs your test suite against each one. A mutant that makes the suite fail is caught; a mutant that passes every test survives. Every survivor is a change your tests let through, and each one is either harmless or a potential bug. The harmless ones are equivalent code no test could distinguish or a branch no execution reaches, and you can set those aside. The rest are a to-do list: each one is a specific test you are missing, a case your suite should check but does not, occasionally with a real bug sitting behind the gap. The primer above describes a real audit where a mutation campaign surfaced a high-severity bug that the project&rsquo;s tests had missed.</p>
<h2 id="mutation-testing-forces-the-unhappy-path">Mutation testing forces the unhappy path</h2>
<p>A DAML contract encodes rights and obligations between named parties: who holds what, who owes what to whom, and who must authorize each step. A party is not an anonymous address. It represents a real organization or person, and the contract is the rulebook for how those parties interact, including which of them can take which action, what each is allowed to see, and what stays private between them.</p>
<p>Authorization is how that rulebook is enforced: who may take which action. It is also easy to get wrong in ordinary ways, such as a typo in a controller clause, a missing party, an extra one left over from a refactor. Every combination type-checks, so nothing rejects it before it ships. A static analyzer can flag suspicious patterns, but it has no way to know which party should hold which authority on your contract. That knowledge lives in your specification, and for most projects, the only executable form of the specification is the test suite. Happy-path tests supply every signature the contract asks for and confirm the transaction succeeds. They never try the negative case—removing a required signature and checking that the ledger rejects the transaction—so they never actually test whether that signature was required at all. If the tests don&rsquo;t encode that rule, nothing downstream can recover it. Mutation testing is what tells you whether they do.</p>
<p>A green test run tells you your tests passed today. Mutation testing asks the harder question: would your tests catch a mistake, now or after the next code change? Where the answer is no, you have found a test case worth writing.</p>
<h2 id="what-mewt-adds-for-daml">What Mewt adds for DAML</h2>
<p>Mewt parses every language it supports with a tree-sitter grammar. As of mid-2026, there is no maintained tree-sitter grammar for DAML, so we reused the upstream <code>tree-sitter-haskell</code> grammar. DAML is Haskell-shaped, but its contract constructs (<code>template</code>, <code>choice</code>, <code>controller</code>, and <code>signatory</code>) are not Haskell, and the grammar parses them as error-recovered subtrees. That matters less than it sounds. The common mutations still work on DAML&rsquo;s ordinary expressions, so Mewt swaps arithmetic and comparison operators, flips Booleans, and removes branches just as it does in any other language, with only small adjustments where DAML&rsquo;s surface syntax differs (DAML writes <code>/=</code> where most languages write <code>!=</code>). We got most of the value of a from-scratch grammar without building one.</p>
<p>The new engineering went into DAML&rsquo;s authorization primitives, where the authorization bugs from the previous section live. Mewt adds two DAML-specific mutations:</p>
<ul>
<li>
<p><strong>Controller party swap</strong> (CPS in Mewt&rsquo;s output): replace one party in a <code>controller</code> clause with another party that is in scope at that site.</p>
</li>
<li>
<p><strong>Controller party removal</strong> (CPR): drop one party from a multi-party controller list.</p>
</li>
</ul>
<p>Both target the same question: if the set of parties allowed to exercise this choice silently changed, would any test fail? They are a deliberately small starting set aimed at the bug class above, and more DAML-specific mutations are in the pipeline.</p>
<p>Driving a campaign needs no new harness. A short <code>mewt.toml</code> names the files to mutate and the test command (<code>dpm test</code> for a Daml 3 project), and <code>mewt run</code> does the rest, reporting each mutant as caught or surviving. The setup is deliberately small: trying it on your own project costs minutes, and we encourage exactly that.</p>
<h2 id="what-a-surviving-mutant-looks-like">What a surviving mutant looks like</h2>
<p>Picture a conditional payment between a buyer and a seller: the buyer sets money aside for the goods, and paying it out to the seller requires both parties to sign off. The buyer&rsquo;s signature is the delivery confirmation. In DAML, that policy is one line: the <code>controller</code> line on the <code>Release</code> choice.</p>
<figure class="highlight">
<pre tabindex="0"><code class="language-" data-lang=""
>template ConditionalPayment
with
buyer : Party
seller : Party
amount : Decimal
where
signatory buyer
observer seller
choice Release : ()
with
paid : Decimal
controller buyer, seller
do
assert (paid == amount)</code></pre>
<figcaption><span>Figure 1: A payment that requires both the buyer and the seller to approve its release</span></figcaption>
</figure>
<p>A typical happy-path test creates the payment and has both parties approve the release. The <code>actAs buyer &lt;&gt; actAs seller</code> line submits the command with both parties&rsquo; authority:</p>
<figure class="highlight">
<pre tabindex="0"><code class="language-" data-lang=""
>testHappyPath : Script ()
testHappyPath = script do
buyer &lt;- allocateParty &#34;Buyer&#34;
seller &lt;- allocateParty &#34;Seller&#34;
payment &lt;- submit buyer do
createCmd ConditionalPayment with
buyer
seller
amount = 100.0
submit (actAs buyer &lt;&gt; actAs seller) do
exerciseCmd payment Release with paid = 100.0
pure ()</code></pre>
<figcaption><span>Figure 2: The happy-path test. It passes, and coverage reports 100%.</span></figcaption>
</figure>
<p>The test passes, and by the usual measure the suite looks complete: running <code>dpm test</code> with coverage reporting enabled shows full coverage.</p>
<figure class="highlight">
<pre tabindex="0"><code class="language-" data-lang=""
>$ dpm test --show-coverage --coverage-ignore-choice Archive
testHappyPath: ok, 0 active contracts, 2 transactions.
- Internal templates: 1 defined, 1 (100.0%) created
- Internal template choices: 1 defined, 1 (100.0%) exercised</code></pre>
<figcaption><span>Figure 3: The coverage report for the happy-path test. Every template is created and every choice is exercised, for 100% coverage.</span></figcaption>
</figure>
<p>The <code>--coverage-ignore-choice Archive</code> flag deserves a word. Every DAML template automatically gets an implicit <code>Archive</code> choice. It is not part of the business logic under test, so we exclude it for simplicity. With it included, this one-choice template would report 50% even though the test exercises everything we wrote.</p>
<p>Run Mewt on the project and it generates seven mutants. The test suite catches three of them. Four survive. Here is one of the survivors, shown as the diff Mewt reports:</p>
<figure class="highlight">
<pre tabindex="0"><code class="language-" data-lang=""
> choice Release : ()
with
paid : Decimal
- controller buyer, seller
&#43; controller seller
do
assert (paid == amount)</code></pre>
<figcaption><span>Figure 4: The controller-removal mutant that survives the test suite</span></figcaption>
</figure>
<p>Re-run the test suite against this mutant. It still passes, and coverage still reports 100%. The contract claims releasing the buyer&rsquo;s money requires both parties. The mutant lets the seller release it to themselves without the buyer ever confirming delivery. The tests report green either way. Only a test that tries the <em>forbidden</em> path, the seller acting alone, expecting the ledger to reject it, can tell the two contracts apart. No such test exists, and the mutation score says so. (The other three survivors tell the same story from different angles: the buyer-alone twin of this mutant, and two mutants that weaken the <code>paid == amount</code> check to <code>&lt;=</code> and <code>&gt;=</code>, which survive because the test only ever pays the exact amount.)</p>
<p>Step back, and this is the whole point of the exercise. Your tests are the executable specification of your code. Here the implementation changed, one required approval instead of two, and the specification did not react. That means the expected behavior was underspecified all along: whether both the buyer and the seller have to sign off, or just one of them, was never actually written down anywhere a machine could check. Every controller combination type-checks, and coverage reports 100% for all of them. The only place &ldquo;both must sign&rdquo; can exist in checkable form is a test that expects the weakened contract to fail, and writing that test is exactly what the surviving mutant tells you to do.</p>
<h2 id="limitations-and-what-comes-next">Limitations and what comes next</h2>
<p>Mewt is not magic. Two limits are worth knowing before you run your first campaign: not every survivor is a real gap, and a campaign costs time. The roadmap that follows them is where we are taking the work next.</p>
<p>Equivalent mutants exist: some survivors turn out to be semantically identical to the original program, so no test could ever catch them. Few public DAML codebases on GitHub come with a full test suite, so we are glad OpenZeppelin open-sourced its <code>canton-stablecoin</code> reference implementation. Mewt generated hundreds of mutants for it. We ran the highest-priority ones through the existing test suite, and seven of those survived. Three were equivalent mutants or sat behind a guard that no path reaches, and the other four were genuine missing test cases. None of the survivors we reviewed pointed to a bug. Such a clean result is what you want when you run Mewt on your own code, and triaging them took minutes.</p>
<p>One of those equivalent mutants shows what that means concretely. A helper computed accrued debt:</p>
<figure class="highlight">
<pre tabindex="0"><code class="language-" data-lang=""
>accrueDebt currentDebt lastAccrual now annualRate =
if currentDebt == 0.0 || annualRate == 0.0 then currentDebt
else
let elapsedYears = ... -- elapsed time as a fraction of a year
in currentDebt * (1.0 &#43; annualRate * elapsedYears)</code></pre>
<figcaption><span>Figure 5: The accrueDebt helper. Its first-line guard is a shortcut that returns the same value the calculation already produces.</span></figcaption>
</figure>
<p>Mewt forced the <code>if</code> to always take the <code>else</code> branch. No test failed, and none ever could: when the debt is zero, the formula multiplies by zero and returns zero, and when the rate is zero, it multiplies the debt by one and returns it unchanged. The guard is a shortcut that returns the value the formula already produces, so removing it changes nothing. Mewt suppresses the equivalent mutants it can detect. The rest need a reviewer&rsquo;s judgment to dismiss.</p>
<p>Campaigns cost time in two places. The machine part: Mewt runs your test suite once per mutant, so the wall-clock cost is roughly the number of mutants times how long one test run takes, plus a rebuild if your project needs one. That is minutes on a small codebase and hours on a large one or a slow suite, so the cadence that works is nightly or weekly rather than per-commit. The human part: someone has to look at the survivors. We are working on that front from several directions at Trail of Bits, including our <a href="https://github.com/trailofbits/skills/tree/main/plugins/mutation-testing">mutation-testing skill</a> that helps configure campaigns for your project, and <a href="https://blog.trailofbits.com/2026/04/23/trailmark-turns-code-into-graphs/">Trailmark</a> with its <code>genotoxic</code> triage skill. None of these understand DAML yet, but the direction is clear: given the right harness and tools, the time-consuming parts of a campaign can be handed to AI agents. The effort is modest and the payoff is concrete: each genuine survivor is a specific test you can write, and every test you add makes your suite enforce one more guarantee your contracts are supposed to make.</p>
<p>Also on the roadmap: choice-consumption mutations (<code>consuming</code> vs <code>nonconsuming</code>) sit cleanly on top of the controller-mutation scaffolding and target a bug class Mewt does not yet reach.</p>
<h2 id="dive-in">Dive in</h2>
<p>Install Mewt from the <a href="https://github.com/trailofbits/mewt">repository</a>, point a <code>mewt.toml</code> at your project and its test command, and <code>mewt run</code>. The quickstart in the README covers the rest. DAML works out of the box. Everything here ran on Daml 3.4 with <code>dpm</code>, but Mewt just drives whatever test command you configure, so Daml 2 projects using the <code>daml</code> assistant work the same way.</p>
<p>Mutation testing complements the rest of your security stack, the type checkers, linters, and property tests you already run, rather than replacing any of it.</p>
<p>If you&rsquo;re building on Canton, we help teams with security reviews of DAML applications and with the way the code gets built: working directly with your engineers on the development process itself. <a href="https://www.trailofbits.com/contact/">Contact us</a>.</p>RE: On Form Factor - Joel's Log Fileshttps://joelchrono.xyz/blog/on-form-factor2026-07-07T21:25:00.000Z<p>Josh, a fellow member of the TWG server, wrote an awesome piece about <a href="https://espressotonic.beehiiv.com/p/on-form-factor">the form factor</a> of the devices and stuff he carries and how that affects the way he uses them! Since we are celebrating <a href="https://robertbirming.com/julyreply/">July Reply</a>, this post seemed like the perfect way for me to reply to!.</p>
<p>In a way, what the premise boils down to is what properties should an object have in order to be used <em>with intent</em> and not ignored?</p>
<p>The way we can afford to spend time intentionally, playing videogames, reading a book or listening to music, is heavily dependant in the context of our lives.</p>
<p>Right now the most time I get to spend doing such activities is on my <a href="/blog/the-time-commuting-to-work">commutes to work</a>, but going to the gym, arriving early to work, or simply being home, come with their own set of situations.</p>
<h2 id="on-commutes">On commutes</h2>
<p>During my commute, I have plenty of advantages. I have free time, I have nothing else to do, and I can carry a backpack with fun trinkets inside.</p>
<p>This means that I can bring my Nintendo Switch and play it the whole trip without any problem. Or any other device for that matter.</p>
<p>However, not all commutes are the same, bringing the Switch is only worth it if my commutes are long and if I really just go from home to work and viceversa.</p>
<p>Sometimes, my commute takes an hour—perfect for some Switch gaming!—but other times, it only takes about 25 minutes, and that makes things a bit more tight. Those shorter sessions are excellent and they were plenty of time for me to complete something like <a href="/blog/metal-gear-solid-peace-walker/"><em>Metal Gear Solid: Peace Walker</em></a> or <em>Fire Emblem Awakening</em>. However, I was lucky enough to have longer commutes when I played <a href="/blog/metroid-prime-remastered/"><em>Metroid Prime Remastered</em></a>.</p>
<p>Ocassionaly, I will get off the work bus on my way back home, and take the public transport, this happens when I’m heading to the gym, or to pick-up a delivery. In such a situation, I don’t dare to bring out my Nintendo Switch in public—I don’t want it stolen—and I won’t take out my PSP either, because the buses here are wild and if I drop it, the battery and its cover popping out who knows where.</p>
<p>Something like my <a href="/blog/the-gba-experience-i-wanted/">Anbernic RG35XX SP</a> is often ideal, much cheaper and smaller, and while not sturdier than the PSP overall, the battery doesn’t pop out—although the cheap plastic will definitely chip.</p>
<p>Of course, this is assuming I can sit. There are seasons where buses will be full of people all the time, and it’s in those moments where my <em>Miyoo Mini Flip</em> comes to the rescue! I actually haven’t used it that much, but when I know I’ll probably have to stand up among lots of people, using it to play one-handed-friendly games is awesome.</p>
<p>However, in that case, I may prefer to read some pages on my <a href="/blog/early-days-with-xteink-x4/">XTEINK X4</a>. And yes, I am one of those weirdos that can actually read while on the move, even on a bus where I keep swaying in every direction at every stop.</p>
<p>Another reason I wouldn’t carry my Switch is because of the added space taken by it. A huge deterrent for me to go to the gym is carrying my extra clothing. I also don’t feel comfortable leaving such a device alone, even when there are locker rooms.</p>
<h2 id="at-the-gym">At the gym</h2>
<p>I don’t use gaming handhelds at the gym. I probably shouldn’t care of what others may think if I did, but I do. Besides, it’s much easier for me to get distracted from the excercise by it, or slowing down my walking pace because of the game. Even if I feel justified when others spend that time on their phones resting for five whole minutes.</p>
<p>I simply stick to a podcast when at the gym, put my earphones and ignore everything else. My body focuses on the excercise and my mind is entertained by an episode of <em>Wolf 359</em>.</p>
<p>However, every once in a while I’ve been bold enough to take out my Kobo reader and read a whole chapter of <em>The Expanse</em> while using the threadmill. I have done the same thing with my XTEINK without much issues.</p>
<p>This is only really useful while on a walk or stationary bike, as most machinery lacks a decent place for me to place the ereader in a good position for me to read. Plus, getting stuck staring at a page I already completed because of an excercise would probably drive me mad.</p>
<p>Indeed, music and podcasts are best here, though the XTEINK’s form factor is nice to carry without feeling uncomfortable on my pocket for the rest of my routine. If it’s my Kobo, I’d have to bring it on hand, leave it on the floor or some other random surfaces, or store it in the locker after the warm-up.</p>
<h2 id="at-work">At work</h2>
<p>To be clear I <em>do not</em> play with my handheld consoles during work hours.</p>
<p>Fine, fine… maybe a casual session of <em>Slice & Dice</em> on my phone every once in a while.</p>
<p>Still, for the longest time the fact that the Kobo looks like paper allowed me to just have it by my side and read a few pages here and there. The form factor was ideal to pass off as a notebook—or maybe people knew sometimes but nobody cared.</p>
<p>Eventually, when the XTEINK came about, things got a lot easier! Although I still use both interchangeably, as it seems not many people mind about telling me to <em>not</em> read books at work…</p>
<p>Oh, right, outside of work hours, I do play with my handhelds sometimes, whenever my commute is short and I arrive early at my workplace! I only do this with smaller form factors, latest of which is my <a href="/blog/nintendo-3ds/">New Nintendo 3DS XL</a>, that has been the largest of the bunch, but still slim enough for me to use before more people start showing up. The Nintendo Switch is way too big and I don’t need to bring attention to it, honestly.</p>
<h2 id="at-home">At home</h2>
<p>Tthe only thing that stops me from gaming, reading, or doing whatever I want, is the fact that I don’t live by myself!</p>
<p>Now, it’s not that I can’t do something I want, I am simply reminded of my responsibilities and aware of the fact that everyone in the house has to fulfill them for the sake of peace, harmony and love!</p>
<p>Because of this, I mostly stick to devices that allow me to have quick sessions, or some leisure time on the TV with my Nintendo Switch, when every duty of mine is taken care of—or when there’s nobody at home to stop me.</p>
<p>I rarely read at home using my Kobo or my XTEINK, if I’m honest, as I would rather spend my time doing things like playing longer games with a narrative that may end up too disjointed when split into short bursts.</p>
<p>This is also the one moment where I actually don’t mind reading a physical book as well, something different from my sci-fi novels or Manga. It’s where I get to read or study the bible, rather than entertainment.</p>
<p>Podcasts also win a lot of ground especially during chores here, great background noise when doing dishes or mopping the floor.</p>
<p>All in all, the form factor matters less when there’s no real limit to what I can do, I guess.</p>
<h2 id="finishing-thoughts">Finishing thoughts</h2>
<p>Josh’s final paragraphs focused on the intentionality of choosing a specific device for a specific moment, for a specific use. Every gadget having a certain meaning, a form factor that makes it ideal for a time, a place, or a state of mind.</p>
<p>Especially so when so much out there is trying to convinced of how encompassing everything into a single point—the smartphone—is the ideal. In the end, it’s all too overwhelming, and overdependence on it only ends up hurting us, being a distraction to what matters in the moment.</p>
<p>That was some pretty good stuff, and I feel I sort of wandered off into what use every device of mine has in many situations. There’s a couple of other things I could have talked about, such as going out shopping or similar, but it’s clear that the tiniest devices are often great when they are meant to fill up empty spaces rather than being the focus.</p>
<p>At last, this is enough for a post, I’d say! I am also going to continue playing some <em>Fire Emblem Awakening</em> on my 3DS after I’m done with this.</p>
<p>This is day 92 of <a href="https://100daystooffload.com">#100DaysToOffload</a>.</p>
<p>
<a href="mailto:me@joelchrono.xyz?subject=RE: On Form Factor">Reply to this post via email</a> |
<a href="https://fosstodon.org/@joel/116880830558317275">Reply on Fediverse</a>
</p>Implementing standard.site on a nonstandard site - Posts feedhttps://www.coryd.dev/posts/2026/implementing-standardsite-on-a-nonstandard-site2026-07-07T21:13:00.000Z<div class="e-content"><p>Now that <a href="https://www.coryd.dev/colophon">this site is written in Go</a><sup id="fnref:1" class="footnote-ref">1</sup>, I've turned to restoring and adding more features connecting it to the open web. While I maintain a healthy skepticism of Bluesky the company, I'm enamored with open protocols and <a href="https://en.wikipedia.org/wiki/AT_Protocol">ATProto</a> falls under that umbrella.</p>
<p>ATProto exists apart from Bluesky and Bluesky is built on top of ATProto.</p>
<p><a href="https://en.wikipedia.org/wiki/AT_Protocol">Wikipedia</a></p>
<blockquote>
<p>The AT Protocol (Authenticated Transfer Protocol, pronounced "at protocol", commonly shortened to ATproto or "ATP") is a protocol and set of open standards for decentralized publishing and distribution of self-authenticating data within the social web. It serves as the technical foundation of the Bluesky social network, originally developed as a reference implementation for the protocol, as well as an ecosystem of interoperable social applications and services collectively referred to as the ATmosphere.</p>
</blockquote>
<p>After reluctantly joining <a href="https://www.coryd.dev/posts/2026/lifting-mastodon-rate-limits">Bluesky</a>, I saw a host of folks implementing <a href="https://standard.site">standard.site</a>.</p>
<blockquote>
<p>Standard.site provides shared lexicons for long-form publishing on AT Protocol. Making content easier to discover, index, and move across the ATmosphere.</p>
</blockquote>
<p>It's another protocol to support, another network, another implementation, another maintenance burden and all that, but it gets you a fancy button and avatar attached to posts. How could I resist?</p>
<p>My implementation is hand-rolled against Bluesky's endpoints since that's where my PDS lives.<sup id="fnref:2" class="footnote-ref">2</sup></p>
<aside>
<p><a href="https://en.wikipedia.org/wiki/AT_Protocol#Personal_Data_Servers">Wikipedia, again:</a> Personal Data Servers (PDSes) host user repositories and their associated media. They also serve as the network access point for users, facilitating repository updates, backups, data queries, and user requests.</p>
</aside>
<article class="entry-card h-entry"><aside class="meta"><time class="dt-published" datetime="2026-07-07T17:21:00Z"><a href="https://www.coryd.dev/links/publishing-on-the-atmosphere-with-standardsite" class="u-url">July 7, 2026</a></time> </aside><h3><a href="https://piccalil.li/blog/publishing-on-the-atmosphere-with-standardsite/?ref=main-rss-feed" title="Publishing on the Atmosphere with Standard.site" class="p-name u-bookmark-of">Publishing on the Atmosphere with Standard.site</a> via <a href="https://vale.rocks">Declan Chidlow</a></h3><blockquote><p>Standard.site provides a set of lexicons for publishing long-form content on the internet using the same protocol used under the hood by Bluesky.</p>
</blockquote><div class="badges"><a href="https://www.coryd.dev/tags/tech" class="badge p-category">tech</a><a href="https://www.coryd.dev/tags/atproto" class="badge p-category">atproto</a><a href="https://www.coryd.dev/tags/bluesky" class="badge p-category">bluesky</a></div></article><h2 id="getting-things-working">Getting things working</h2>
<p>There are two record types that are required as part of this implementation: <code>site.standard.publication</code> which describes the site — name, description, url, theme and icon. <code>site.standard.document</code> is a record required for each piece of content, each pointing back to my site (the publication).</p>
<p>When I post a link the <a href="https://en.wikipedia.org/wiki/AT_Protocol#AppViews">AppView</a> crawls the page looking for two tags: <code><link rel="site.standard.document"></code> and <code><link rel="site.standard.publication"></code>. These tags have <code>href</code> attributes that are resolved against my PDS, verifying ownership by also fetching my <a href="https://www.coryd.dev/.well-known/site.standard.publication">/.well-known/site.standard.publication</a> endpoint.</p>
<p>I use a handful of <a href="https://riverqueue.com">River</a> jobs to make this work. Records are authored as plain <code>map[string]any</code> objects that are marshalled to JSON and <code>PUT</code> via <code>com.atproto.repo.putRecord</code>.</p>
<p>I post a bunch of different content types on this site, many of which are syndicated to Mastodon and Bluesky and each type that is syndicated is now published as part of the standard.site implementation. The shape of syndicated content is typically: title, description, hashtags and a link to the content. Only movies, books and concerts I've written something about are syndicated, while all posts are syndicated. The query to fetch movie data from my <a href="https://www.postgresql.org">PostgreSQL</a> database looks like this:</p>
<pre class="language-sql"><code class="language-sql"><span class="token keyword">SELECT</span> title<span class="token punctuation">,</span> COALESCE<span class="token punctuation">(</span>description<span class="token punctuation">,</span><span class="token string">''</span><span class="token punctuation">),</span> url<span class="token punctuation">,</span> last_watched<span class="token punctuation">,</span> COALESCE<span class="token punctuation">(</span>tags<span class="token punctuation">,</span><span class="token string">'{}'</span><span class="token punctuation">)</span> <span class="token keyword">FROM</span> optimized_movies <span class="token keyword">WHERE</span> review <span class="token keyword">IS</span> <span class="token keyword">NOT</span> <span class="token keyword">NULL</span> <span class="token keyword">AND</span> review <span class="token operator">!=</span> <span class="token string">''</span> <span class="token keyword">AND</span> last_watched <span class="token keyword">IS</span> <span class="token keyword">NOT</span> <span class="token keyword">NULL</span> <span class="token keyword">ORDER</span> <span class="token keyword">BY</span> last_watched <span class="token keyword">DESC</span>
</code></pre>
<p>The constructed document record looks like this:</p>
<pre class="language-go"><code class="language-go">record <span class="token operator">:=</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{</span>
<span class="token string">"$type"</span><span class="token punctuation">:</span> <span class="token string">"site.standard.document"</span><span class="token punctuation">,</span>
<span class="token string">"site"</span><span class="token punctuation">:</span> publicationURI<span class="token punctuation">,</span> <span class="token comment">// AT-URI back to the publication</span>
<span class="token string">"title"</span><span class="token punctuation">:</span> item<span class="token punctuation">.</span>Title<span class="token punctuation">,</span>
<span class="token string">"publishedAt"</span><span class="token punctuation">:</span> item<span class="token punctuation">.</span>Date<span class="token punctuation">.</span><span class="token function">UTC</span><span class="token punctuation">().</span><span class="token function">Format</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>RFC3339<span class="token punctuation">),</span>
<span class="token string">"path"</span><span class="token punctuation">:</span> item<span class="token punctuation">.</span>URL<span class="token punctuation">,</span> <span class="token comment">// also the rkey seed</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The publication record looks like this:</p>
<pre class="language-go"><code class="language-go"><span class="token operator">...</span>
record <span class="token operator">:=</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{</span>
<span class="token string">"$type"</span><span class="token punctuation">:</span> <span class="token string">"site.standard.publication"</span><span class="token punctuation">,</span>
<span class="token string">"name"</span><span class="token punctuation">:</span> name<span class="token punctuation">,</span>
<span class="token string">"url"</span><span class="token punctuation">:</span> siteURL<span class="token punctuation">,</span>
<span class="token string">"preferences"</span><span class="token punctuation">:</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{</span>
<span class="token string">"showInDiscover"</span><span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">,</span>
<span class="token punctuation">},</span>
<span class="token string">"basicTheme"</span><span class="token punctuation">:</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{</span>
<span class="token string">"$type"</span><span class="token punctuation">:</span> <span class="token string">"site.standard.theme.basic"</span><span class="token punctuation">,</span>
<span class="token string">"background"</span><span class="token punctuation">:</span> <span class="token function">rgbColor</span><span class="token punctuation">(</span><span class="token number">239</span><span class="token punctuation">,</span> <span class="token number">242</span><span class="token punctuation">,</span> <span class="token number">246</span><span class="token punctuation">),</span>
<span class="token string">"foreground"</span><span class="token punctuation">:</span> <span class="token function">rgbColor</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">14</span><span class="token punctuation">,</span> <span class="token number">19</span><span class="token punctuation">),</span>
<span class="token string">"accent"</span><span class="token punctuation">:</span> <span class="token function">rgbColor</span><span class="token punctuation">(</span><span class="token number">78</span><span class="token punctuation">,</span> <span class="token number">83</span><span class="token punctuation">,</span> <span class="token number">89</span><span class="token punctuation">),</span>
<span class="token string">"accentForeground"</span><span class="token punctuation">:</span> <span class="token function">rgbColor</span><span class="token punctuation">(</span><span class="token number">239</span><span class="token punctuation">,</span> <span class="token number">242</span><span class="token punctuation">,</span> <span class="token number">246</span><span class="token punctuation">),</span>
<span class="token punctuation">},</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> description <span class="token operator">!=</span> <span class="token string">""</span> <span class="token punctuation">{</span>
record<span class="token punctuation">[</span><span class="token string">"description"</span><span class="token punctuation">]</span> <span class="token punctuation">=</span> description
<span class="token punctuation">}</span>
<span class="token keyword">if</span> icon <span class="token operator">!=</span> <span class="token keyword">nil</span> <span class="token punctuation">{</span>
record<span class="token punctuation">[</span><span class="token string">"icon"</span><span class="token punctuation">]</span> <span class="token punctuation">=</span> icon
<span class="token punctuation">}</span>
<span class="token keyword">return</span> record
<span class="token operator">...</span>
</code></pre>
<aside>
<p>The icon referenced here isn't a URL. <code>atproto</code> records reference blobs, so I fetched my existing OG image and uploaded it to the PDS first, then dropped the returned blob ref into the record. I derived the theme colors from the canonical <code>vars.css</code> used to style my site.</p>
</aside>
<p>I created a pair of standard.site specific commands in the CMS for this site. One to sync my site record to my PDS and another to sync my backlog of posts. I ran both, verified the records, tried a test post and nothing happened. I hoped it was a caching or propagation issue, waited and still nothing. I hit a few walls building this but, being unreasonably stubborn, I continued on.</p>
<h3 id="bug-1-apex-vs-www">Bug 1: apex vs. www</h3>
<p>As best I can tell, the <code>AppView</code> verifies my <code>.well-known</code> endpoint using a non-JavaScript call. My username on Bluesky is my apex domain but that redirects to <code>www</code>. I set the site record to <code>www.coryd.dev</code> and allowed the <code>.well-known</code> path to resolve at the apex in my Caddy config.</p>
<h3 id="bug-2-set-a-stable-record-key">Bug 2: set a stable record key</h3>
<p>For this to work, the record key in Bluesky <em>must</em> match the one embedded in the head of each document. However, a number of my content types have a published date that can shift over time — books when I read them again and movies when I watch them again. I store a record for each read and watch but the published date is updated to the most recent each time. I chose to derive the <code>rkey</code> from the URL for each content type alone.</p>
<aside>
<p>Every record on a PDS lives in a collection at a record key. Its address is <code>at://{my-did}/site.standard.document/{rkey}</code>. I get to choose the <code>rkey</code> which, naturally, is how I managed to break things.</p>
</aside>
<pre class="language-go"><code class="language-go"><span class="token keyword">func</span> <span class="token function">ATProtoTID</span><span class="token punctuation">(</span>urlPath <span class="token class-name">string</span><span class="token punctuation">)</span> <span class="token class-name">string</span> <span class="token punctuation">{</span>
h <span class="token operator">:=</span> fnv<span class="token punctuation">.</span><span class="token function">New64a</span><span class="token punctuation">()</span>
_<span class="token punctuation">,</span> _ <span class="token punctuation">=</span> h<span class="token punctuation">.</span><span class="token function">Write</span><span class="token punctuation">([]</span><span class="token class-name">byte</span><span class="token punctuation">(</span>urlPath<span class="token punctuation">))</span>
n <span class="token operator">:=</span> h<span class="token punctuation">.</span><span class="token function">Sum64</span><span class="token punctuation">()</span> <span class="token operator">&</span> <span class="token number">0x7FFFFFFFFFFFFFFF</span>
<span class="token comment">// base32-encode to 13 chars</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Each URL is unique, stored with the record and can be used to derive a stable <code>rkey</code>.</p>
<h3 id="bug-3-theme-object-validation">Bug 3: theme object validation</h3>
<p>A simple, but fun one: failing to set <code>$type</code> on the theme object will cause the publication block to be dropped by the Bluesky parser.</p>
<p>I solved this one by comparing the structure of my publication record to Mat Maquis', line by line, after reading his <a href="https://wil.to/posts/implementing-standard-site/">implementation post</a>.</p>
<h2 id="stapling-things-together">Stapling things together</h2>
<p>When I syndicate something to Bluesky, the external embed carries a pair of references pointing at the document and publication:</p>
<pre class="language-go"><code class="language-go"><span class="token keyword">if</span> refs <span class="token operator">:=</span> w<span class="token punctuation">.</span><span class="token function">standardSiteRefs</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> session<span class="token punctuation">,</span> content<span class="token punctuation">);</span> <span class="token class-name">len</span><span class="token punctuation">(</span>refs<span class="token punctuation">)</span> <span class="token punctuation">></span> <span class="token number">0</span> <span class="token punctuation">{</span>
external<span class="token punctuation">[</span><span class="token string">"associatedRefs"</span><span class="token punctuation">]</span> <span class="token punctuation">=</span> refs
<span class="token punctuation">}</span>
record<span class="token punctuation">[</span><span class="token string">"embed"</span><span class="token punctuation">]</span> <span class="token punctuation">=</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{</span>
<span class="token string">"$type"</span><span class="token punctuation">:</span> <span class="token string">"app.bsky.embed.external"</span><span class="token punctuation">,</span>
<span class="token string">"external"</span><span class="token punctuation">:</span> external<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre>
<p>To properly derive these, the syndicated document has to be on the PDS before Bluesky indexes the post:</p>
<pre class="language-go"><code class="language-go"><span class="token comment">// Bluesky is delayed so the standard.site document record lands on the PDS</span>
<span class="token comment">// before Bluesky indexes the post</span>
<span class="token punctuation">{</span>jobs<span class="token punctuation">.</span>SyncSingleStandardSiteDocumentArgs<span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">},</span> <span class="token operator">&</span>river<span class="token punctuation">.</span>InsertOpts<span class="token punctuation">{</span>UniqueOpts<span class="token punctuation">:</span> dedupeInFlight<span class="token punctuation">}},</span>
<span class="token punctuation">{</span>jobs<span class="token punctuation">.</span>SyndicateToBlueskyArgs<span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">},</span> <span class="token operator">&</span>river<span class="token punctuation">.</span>InsertOpts<span class="token punctuation">{</span>
ScheduledAt<span class="token punctuation">:</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">().</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token number">30</span> <span class="token operator">*</span> time<span class="token punctuation">.</span>Second<span class="token punctuation">),</span> UniqueOpts<span class="token punctuation">:</span> dedupeInFlight<span class="token punctuation">}},</span>
</code></pre>
<aside>
<p>Each ref is a <code>strongRef</code>: a record's <code>AT-URI</code> paired with a hash of its exact contents. This allows the embed to tell Bluesky precisely which document and publication this link maps to, rather than making it recrawl the page.</p>
</aside>
<p>The other fun part of this all is that these failures (inasmuch as Bluesky was concerned) were silent. My implementation passed the available validators I tried and the published records passed the eye test, but they failed Bluesky's validation.</p>
<article class="entry-card h-entry"><div class="status-card-body"><aside class="meta"><time class="dt-published" datetime="2026-06-13T03:24:00Z"><a href="https://www.coryd.dev/status/this-standardsite-2026-06-13-03-24-25" class="u-url">June 13, 2026</a></time> <span aria-hidden="true">•</span> <a href="https://www.coryd.dev/status">Status</a></aside><div class="e-content"><p>This standard.site stuff is super confusing</p>
</div><a class="u-url visually-hidden" href="https://www.coryd.dev/status/this-standardsite-2026-06-13-03-24-25" aria-hidden="true" tabindex="-1">/status/this-standardsite-2026-06-13-03-24-25</a></div></article><h3 id="actually-publishing">Actually publishing</h3>
<p>Every job authenticates when run using an app password against <code>com.atproto.server.createSession</code> which returns a short-lived bearer token (<code>accessJwt</code>) and confirms my <code>DID</code>:</p>
<pre class="language-go"><code class="language-go"><span class="token keyword">func</span> <span class="token function">atprotoCreateSession</span><span class="token punctuation">(</span>ctx context<span class="token punctuation">.</span>Context<span class="token punctuation">,</span> identifier<span class="token punctuation">,</span> appPassword <span class="token class-name">string</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token operator">*</span>blueskySession<span class="token punctuation">,</span> <span class="token class-name">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
body<span class="token punctuation">,</span> _ <span class="token operator">:=</span> json<span class="token punctuation">.</span><span class="token function">Marshal</span><span class="token punctuation">(</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">string</span><span class="token punctuation">{</span>
<span class="token string">"identifier"</span><span class="token punctuation">:</span> identifier<span class="token punctuation">,</span>
<span class="token string">"password"</span><span class="token punctuation">:</span> appPassword<span class="token punctuation">,</span>
<span class="token punctuation">})</span>
<span class="token comment">// POST to /xrpc/com.atproto.server.createSession → { accessJwt, did }</span>
<span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Once I have the token, I can write the document record:</p>
<pre class="language-go"><code class="language-go"><span class="token keyword">func</span> <span class="token function">atprotoPutRecord</span><span class="token punctuation">(</span>ctx context<span class="token punctuation">.</span>Context<span class="token punctuation">,</span> session <span class="token operator">*</span>blueskySession<span class="token punctuation">,</span> collection<span class="token punctuation">,</span> rkey <span class="token class-name">string</span><span class="token punctuation">,</span> record <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">)</span> <span class="token class-name">error</span> <span class="token punctuation">{</span>
body<span class="token punctuation">,</span> _ <span class="token operator">:=</span> json<span class="token punctuation">.</span><span class="token function">Marshal</span><span class="token punctuation">(</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{</span>
<span class="token string">"repo"</span><span class="token punctuation">:</span> session<span class="token punctuation">.</span>DID<span class="token punctuation">,</span>
<span class="token string">"collection"</span><span class="token punctuation">:</span> collection<span class="token punctuation">,</span>
<span class="token string">"rkey"</span><span class="token punctuation">:</span> rkey<span class="token punctuation">,</span>
<span class="token string">"record"</span><span class="token punctuation">:</span> record<span class="token punctuation">,</span>
<span class="token punctuation">})</span>
<span class="token comment">// POST /xrpc/com.atproto.repo.putRecord with Authorization: Bearer <accessJwt></span>
<span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre>
<p><code>putRecord</code> creates the record if the <code>rkey</code> is unique and updates it if not. I can re-run my backlog sync safely knowing that it will update old records and add new ones but not destroy anything.</p>
<p>Syndicating to Bluesky itself is a separate and straightforward process. The record looks like this:</p>
<pre class="language-go"><code class="language-go">record <span class="token operator">:=</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{</span>
<span class="token string">"$type"</span><span class="token punctuation">:</span> <span class="token string">"app.bsky.feed.post"</span><span class="token punctuation">,</span>
<span class="token string">"text"</span><span class="token punctuation">:</span> text<span class="token punctuation">,</span>
<span class="token string">"createdAt"</span><span class="token punctuation">:</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">().</span><span class="token function">UTC</span><span class="token punctuation">().</span><span class="token function">Format</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>RFC3339<span class="token punctuation">),</span>
<span class="token string">"langs"</span><span class="token punctuation">:</span> <span class="token punctuation">[]</span><span class="token class-name">string</span><span class="token punctuation">{</span><span class="token string">"en"</span><span class="token punctuation">},</span>
<span class="token punctuation">}</span>
</code></pre>
<p>Unlike Mastodon, however, you can't simply send text. For tags to be active rather than plain text, you have to attach them as <code>facets</code>:</p>
<pre class="language-go"><code class="language-go">hashRE <span class="token operator">:=</span> regexp<span class="token punctuation">.</span><span class="token function">MustCompile</span><span class="token punctuation">(</span><span class="token string">`#([a-zA-Z][a-zA-Z0-9_]*)`</span><span class="token punctuation">)</span>
<span class="token keyword">for</span> _<span class="token punctuation">,</span> m <span class="token operator">:=</span> <span class="token keyword">range</span> hashRE<span class="token punctuation">.</span><span class="token function">FindAllStringIndex</span><span class="token punctuation">(</span>text<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
tag <span class="token operator">:=</span> text<span class="token punctuation">[</span>m<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">+</span><span class="token number">1</span> <span class="token punctuation">:</span> m<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]]</span>
facets <span class="token punctuation">=</span> <span class="token class-name">append</span><span class="token punctuation">(</span>facets<span class="token punctuation">,</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{</span>
<span class="token string">"index"</span><span class="token punctuation">:</span> <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">int</span><span class="token punctuation">{</span><span class="token string">"byteStart"</span><span class="token punctuation">:</span> m<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">],</span> <span class="token string">"byteEnd"</span><span class="token punctuation">:</span> m<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]},</span>
<span class="token string">"features"</span><span class="token punctuation">:</span> <span class="token punctuation">[]</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token class-name">string</span><span class="token punctuation">]</span><span class="token class-name">any</span><span class="token punctuation">{{</span><span class="token string">"$type"</span><span class="token punctuation">:</span> <span class="token string">"app.bsky.richtext.facet#tag"</span><span class="token punctuation">,</span> <span class="token string">"tag"</span><span class="token punctuation">:</span> tag<span class="token punctuation">}},</span>
<span class="token punctuation">})</span>
<span class="token punctuation">}</span>
</code></pre>
<p>You have to do the same for URLs (<code>facet#link</code>) and handles (<code>facet#mention</code> — this also requires resolving the handle to a DID, not providing the readable name). It's also worth noting that Bluesky uses <code>createRecord</code> rather than <code>putRecord</code> here which creates its own fresh <code>rkey</code>:</p>
<pre class="language-go"><code class="language-go">req<span class="token punctuation">,</span> _ <span class="token operator">:=</span> http<span class="token punctuation">.</span><span class="token function">NewRequestWithContext</span><span class="token punctuation">(</span>ctx<span class="token punctuation">,</span> http<span class="token punctuation">.</span>MethodPost<span class="token punctuation">,</span>
blueskyPDSURL<span class="token operator">+</span><span class="token string">"/xrpc/com.atproto.repo.createRecord"</span><span class="token punctuation">,</span> <span class="token operator">...</span><span class="token punctuation">)</span>
</code></pre>
<p>I want a new post each time (hence the new <code>rkey</code>), but also need to guard against duplicate posts (this is called in every syndication dispatch):</p>
<pre class="language-go"><code class="language-go"><span class="token keyword">var</span> dedupeInFlight <span class="token punctuation">=</span> river<span class="token punctuation">.</span>UniqueOpts<span class="token punctuation">{</span>
ByArgs<span class="token punctuation">:</span> <span class="token keyword">true</span><span class="token punctuation">,</span>
ByState<span class="token punctuation">:</span> <span class="token punctuation">[]</span>rivertype<span class="token punctuation">.</span>JobState<span class="token punctuation">{</span>
rivertype<span class="token punctuation">.</span>JobStatePending<span class="token punctuation">,</span>
rivertype<span class="token punctuation">.</span>JobStateScheduled<span class="token punctuation">,</span>
rivertype<span class="token punctuation">.</span>JobStateAvailable<span class="token punctuation">,</span>
rivertype<span class="token punctuation">.</span>JobStateRunning<span class="token punctuation">,</span>
rivertype<span class="token punctuation">.</span>JobStateRetryable<span class="token punctuation">,</span>
<span class="token punctuation">},</span>
<span class="token punctuation">}</span>
</code></pre>
<p><code>ByArgs</code> ensures uniqueness by checking the job's args, <code>ByState</code> monitors the queue state and discards duplicate syndication attempts from the UI. Retryable is in the list to prevent a second insert while a job is waiting to auto-retry after a transient failure.</p>
<aside>
<p>These guards aren't unique to Bluesky but are worth mentioning.</p>
</aside>
<hr/>
<p>With all of that in place — the manual testing, random debug posts, reading of documentation, re-reading of documentation, cycles of frustration and endless deployments — I now sport a shiny publication bar for shared posts on Bluesky.</p>
<div class="footnotes" role="doc-endnotes"><hr/><ol><li id="fn:1"><p>More on that, bit by bit, later. ↩</p>
</li><li id="fn:2"><p>I'll probably move to a self-hosted PDS eventually, but the complexity of this implementation scared me away from doing so for now. ↩</p>
</li></ol></div></div>📝 2026-07-07 18:43: Guinea fowl keets are doing great too. All 5 are loving life with their foster... - Kev Quirkhttps://kevquirk.com/2026-07-07-18432026-07-07T17:43:00.000Z<p>Guinea fowl keets are doing great too. All 5 are loving life with their foster mums.</p>
<p><img loading="lazy" src="https://kevquirk.com/content/images/2026-07-07-1843/1000010240.webp" alt="1000010240" /></p>
<p><img loading="lazy" src="https://kevquirk.com/content/images/2026-07-07-1843/1000010242.webp" alt="1000010242" /></p>
<p><img loading="lazy" src="https://kevquirk.com/content/images/2026-07-07-1843/1000010243.webp" alt="1000010243" /></p>
<p><img loading="lazy" src="https://kevquirk.com/content/images/2026-07-07-1843/1000010246.webp" alt="1000010246" /></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=%F0%9F%93%9D%202026-07-07%2018%3A43">reply to this post by email</a>, or <a href="https://kevquirk.com/2026-07-07-1843#comments">leave a comment</a>.</p>
</div>📝 2026-07-07 18:34: We now have 3 chicks - two white and one black. - Kev Quirkhttps://kevquirk.com/2026-07-07-18342026-07-07T17:34:00.000Z<p>We now have 3 chicks - two white and one black.</p>
<p><img loading="lazy" src="https://kevquirk.com/content/images/2026-07-07-1834/1000010239.webp" alt="1000010239" /></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=%F0%9F%93%9D%202026-07-07%2018%3A34">reply to this post by email</a>, or <a href="https://kevquirk.com/2026-07-07-1834#comments">leave a comment</a>.</p>
</div>CNN and CNBC promote gambling to make a cheap buck - Werd I/O6a4d3079ffd4800001dcb3dd2026-07-07T16:59:37.000Z<p>Link: <a href="https://www.publicnotice.co/p/kalshi-cnn-cnbc?ref=werd.io"><em>How Kalshi infects the news, by Aaron Rupar and Judd Legum in Public Notice and Popular Information</em></a></p><p>Kalshi’s deals with newsrooms seem to be paying dividends for the company:</p><blockquote>“Since December CNBC has published 58 articles that do little more than advertise the existence of a Kalshi market related to a news event. […] Since April, CNBC has employed a <a href="https://www.cnbc.com/davis-giangiulio/?ref=werd.io">dedicated reporter</a> to produce these articles. CNBC also maintains a <a href="https://www.cnbc.com/markets/prediction-markets/?ref=werd.io">page</a> on its website featuring Kalshi prediction markets selected by CNBC editors, along with its web coverage. […] In at least 22 cases, CNBC has written about Kalshi and not disclosed its financial conflict.”</blockquote><p><a href="https://www.axios.com/2025/12/02/cnn-kalshi-prediction-market-data?ref=werd.io">CNN doesn’t pay for access</a>, and instead is <a href="https://www.newyorker.com/news/the-lede/americas-betting-craze-has-spread-to-its-news-networks?_sp=bc5180fe-4e8b-4c96-a107-44eca35ac553.1783442134229&ref=werd.io">paid to exclusively promote Kalshi</a>. <a href="https://www.publicnotice.co/p/kalshi-cnn-cnbc?ref=werd.io">CNBC reporting carries a disclosure</a> which states that its relationship goes further: “CNBC and Kalshi have a commercial relationship that includes customer acquisition and a minority investment.” CNBC will gain financially if its coverage leads to more signups or a growth in Kalshi’s valuation. CNN’s is a simpler paid placement, but both deals are aggressive ways for Kalshi to compete with Polymarket, which has been making similar deals with newsrooms like Yahoo Finance.</p><p>This is even happening when markets are not significant enough to be newsworthy. <a href="https://www.newyorker.com/news/the-lede/americas-betting-craze-has-spread-to-its-news-networks?_sp=bc5180fe-4e8b-4c96-a107-44eca35ac553.1783442134229&ref=werd.io">As the New Yorker noted in December</a>:</p><blockquote>“When Enten lauded the benefits of analyzing betting odds, on air the other day, he failed to mention that only several hundred thousand dollars had been bet on that particular market. Kalshi’s odds provided good fodder for television, but, statistically speaking, they didn’t say much.”</blockquote><p>It reminds me of the deals Twitter made with newsrooms relatively early in its life. Suddenly, almost out of nowhere, anchors read out tweets on the news, and shows promoted their official Twitter accounts over their websites. This didn’t happen organically: Twitter partnerships teams made deals behind the scenes to ensure their product was showcased well. It was one of the first times that a web startup impactfully executed on a media strategy, and startups have built on that pattern ever since.</p><p>Here, rather than serving a social network, money is changing hands for newsrooms to promote gambling markets — and in CNBC’s case, they will make more money if more people gamble. It’s obviously weirder, and the incentives here would pull at traditional newsroom ethics in an uncomfortable way even if the adequate disclosures were published. This comes at an unfortunate time when trust in news is falling quickly, and newsrooms like CNN are increasingly seen as serving their owners rather than bastions of trustworthy reporting. These Kalshi deals are weird, and an obvious conflict of interest that will likely drive people to trust the news even less than they do today.</p><p>The Reuters Institute’s 2026 Digital News Report found that <a href="https://reutersinstitute.politics.ox.ac.uk/digital-news-report/2026?ref=werd.io">70% of respondents think media owners and corporate parents exert undue influence on the news</a>. As more of these sorts of deals are made, and as trust in news continues to decline, newsrooms are going to need to more overtly state that their coverage is free from this sort of sponsored content. Stronger, more transparent ethics statements, and louder conversations about how reporting decisions are made, will help some newsrooms to explain how they stand apart from these dynamics. In the meantime, CNN and CNBC are helping to drive trust in media into the gutter.</p>How I lost my phone - Joel's Log Fileshttps://joelchrono.xyz/blog/lost-phone2026-07-07T15:20:00.000Z<p>Yesterday after work I got in the bus back home and proceeded to happily play on my <a href="/blog/nintendo-3ds/">Nintendo 3DS</a> for the whole trip. I was about to finish a stage of <em>Fire Emblem Awakening</em>, leveling up a lot of characters, dodging attacks and surviving hits, all nice and well!</p>
<p>Then the ride was over, I noticed I was the last person left in the vehicle, I rushed to the exit and stepped out to the street. Ten seconds later, I realized I did not have my phone with me.</p>
<p>My workplace provides us with free transportation, so there are contacts and people in charge who may be able to help me out, I just didn’t know who they are.</p>
<p>Thankfully, I didn’t lose my work phone. I started messaging people from there, a coworker who may know someone, or another peer who uses the same bus.</p>
<p>I manage to join the WhatsApp group of the bus route, where I can finally contact the transport manager, but I got no reply back.</p>
<p>I decide to let my boss know, to see if he could help me find someone else to ask around, he told me he would look into it as well. I was stressed out of my mind.</p>
<p>Running back home like a madman, I dash to my room and my laptop and check to see if Google’s <em>Find My Device</em> works—I remembered my Google account was never logged in. Sometimes you wonder if a degoogled life is even worth it. LOL</p>
<p>Both Signal and WhatsApp can work without having the device online nowadays, so I was able to message a bunch of people and let them know I could be offline for a while, I may even have to change phone numbers because of this, but I wasn’t fully giving up yet.</p>
<p>Another advantage I had is that I still keep my older Xiaomi phone, and even though the power button was acting up, it decided to behave for once and turn on after a charge. I was able to log-in to my bank apps from there and keep an eye on them. That also meant that not every single picture was lost.</p>
<p>Oh, how many things I would have lost… My chat history, all the photos I’ve taken on my Nothing 3(a), my AntennaPod stats, one of my banking apps. I’d have to redownload all my music too, which is annoying.</p>
<p>Eventually, my boss tells me he gave my contact info to someone in HR, and few more minutes later I’m sent photos of the lost device. That brings me relief, as I’m told the transport supervisor has it and that I can check with him tomorrow—which is today now.</p>
<p>My phone is safe and sound, and now it’s back in my hands, peace of mind returns.</p>
<p>Clearly, it’s a bad idea not to check where your belongings are before getting out of a bus. It’s also not ideal to get too distracted by a videogame or to rush things—definitely double-checking from now on. This was honestly one of the most ideal scenarios ever, there are a lot of things that could have gone very very wrong.</p>
<p>I could have left my work phone there as well, my boss could have ignored me completely, I could have no access to Signal/WhatsApp on my laptop, or lack a secondary phone to check my bank accounts, I could have taken a public bus with no ties to my workplace, the bus driver could have kept the device for himself, or the bus manager, a simple lie is all it takes. Thank God it’s all over now, and nothing was lost.</p>
<p>Later I realized I <em>do</em> have <em>Find My Device</em>, I was using a blank Google account untied from anything but that specific phone, so I forgot. I did have the login info backed up, so in the future I can make use of this. Although it would probably have been stressful to see my phone somewhere without being able to do much about it.</p>
<p>Make your backups guys! And also, if you know some good way to track your device without using Google services, let me know!</p>
<p>At the very least, I guess that being able to not be glued to my phone for ten seconds is a good thing, so… <em>win?</em></p>
<p>This is day 91 of <a href="https://100daystooffload.com">#100DaysToOffload</a></p>
<p>
<a href="mailto:me@joelchrono.xyz?subject=How I lost my phone">Reply to this post via email</a> |
<a href="https://fosstodon.org/@joel/116879394050333528">Reply on Fediverse</a>
</p>📝 2026-07-07 07:06: First two chicks! - Kev Quirkhttps://kevquirk.com/2026-07-07-07062026-07-07T06:06:00.000Z<p>First two chicks!</p>
<p><img loading="lazy" src="https://kevquirk.com/content/images/2026-07-07-0706/1000010230.webp" alt="1000010230" /></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=%F0%9F%93%9D%202026-07-07%2007%3A06">reply to this post by email</a>, or <a href="https://kevquirk.com/2026-07-07-0706#comments">leave a comment</a>.</p>
</div>Finished reading Wasteland Warlords 1 - Molly White's activity feed6a4c7ae291f30f1ebeded41f2026-07-07T04:04:50.000Z<article class="entry h-entry hentry"><header><div class="description">Finished reading: </div></header><div class="content e-content"><div class="book h-entry hentry"><a class="book-cover-link" href="https://www.mollywhite.net/reading/books?search=Wasteland%20Warlords%201"><img class="u-photo book-cover" src="https://m.media-amazon.com/images/S/compressed.photo.goodreads.com/books/1698673897i/201044505.jpg" alt="Cover image of Wasteland Warlords 1" style="max-width: 300px;"/></a><div class="book-details"><div class="top"><div class="series-info"><i>Wasteland Warlords</i> series, book <span class="series-number">1</span>. </div><div class="title-and-byline"><div class="title"><i class="p-name">Wasteland Warlords 1</i> </div><div class="byline">by <span class="p-author h-card">James A. Hunter</span> and <span class="p-author h-card">Eden Hudson</span>. </div></div><div class="book-info">Published <time class="dt-published published" datetime="2023">2023</time>. 150 pages. </div></div><div class="bottom"><div class="reading-info"><div class="reading-dates"> Started <time class="dt-accessed accessed" datetime="2026-07-06">July 6, 2026</time>; completed July 6, 2026. </div></div></div></div></div><img src="https://www.mollywhite.net/assets/images/placeholder_social.png" alt="Illustration of Molly White sitting and typing on a laptop, on a purple background with 'Molly White' in white serif." style="display: none;"/></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <time class="dt-published" datetime="2026-07-07T04:04:50+00:00" title="July 7, 2026 at 4:04 AM UTC">July 7, 2026 at 4:04 AM UTC</time>. </div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=fantasy" title="See all books tagged "fantasy"" rel="category tag">fantasy</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=litrpg" title="See all books tagged "litRPG"" rel="category tag">litRPG</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=post_apocalyptic" title="See all books tagged "post-apocalyptic"" rel="category tag">post-apocalyptic</a>. </div></div></footer></article>Purpose, mission, values - Johnny.Decimalhttps://johnnydecimal.com/blog/0229-purpose-mission-values/2026-07-07T02:00:00.000Z<p>After <a href="https://johnnydecimal.com/blog/0228/">discussing this at the last small business meeting</a>, we've thought about and written down our purpose, mission, and values. I'll put a copy here, and add them to their proper home which is our <a href="https://johnnydecimal.com/support/about-legal/policies">policies page</a>. If it's much later than July 2026 when you read this, you should check there for the latest version. This post won't change.</p>
<p>With thanks to <a href="https://oldstructures.nyc">Don</a> and <a href="https://lovettsundries.com">Jeff</a> for the interesting discussion. Don kindly shared a section of his company manual with us, which really helped.</p>
<hr>
<h2 id="purpose">Purpose</h2>
<blockquote>
<p><em>Why do we exist?</em></p>
</blockquote>
<p>In the 1980s, it was possible to live your life without using a computer. You might have made furniture by hand and driven it to a store that sold it for you. You paid the road toll with coins and received a paper receipt, your invoice was hand-typed and recorded in a ledger, and your tax return was filled in with a pen. This generated a small handful of physical documentation which was easily managed using a concertina folder: a basic skill you had been taught at school.</p>
<p>The volume of information was manageable. <strong>You could find anything, quickly and easily</strong>.</p>
<p>Today, that same carpenter – whose job has not changed – needs online accounts for her eToll account and the invoicing software that interfaces with the furniture store and her accountant. Both of these send important documents to her Gmail, which is full of transactional email from the 142 other organisations that she routinely deals with, and the social media accounts that she needs to maintain. Parking her 1982 Land Cruiser outside the furniture store now requires an app.</p>
<p>To help her manage this, her computer provides tools no more sophisticated than <code>Create New Folder</code>. It allows her to save anything anywhere she wants. It positively encourages the duplication of information. At no point was she given any training in these systems, which change constantly and without warning. The people who understand them charge hundreds of dollars an hour.</p>
<p>The volume of information is unmanageable. <strong>Nobody can find anything any more</strong>. This is stressful and inefficient. Computers were meant to make our lives easier. In this regard, they have done the opposite.</p>
<h2 id="mission">Mission</h2>
<blockquote>
<p><em>What are we going to do about it?</em></p>
</blockquote>
<p>We help people manage their information. This information is mostly, but not exclusively, on a computer.</p>
<p>We do this using the Johnny.Decimal system. It's a simple way to organise any information. It provides:</p>
<ol>
<li>A simple structure that uses numbers instead of the alphabet.</li>
<li>An index of your content that you manage.</li>
<li>Training, software, and support.</li>
</ol>
<p>We will be the training you never got: we'll show you how to store things so that you can find them again.</p>
<p>We can't make it so that our carpenter doesn't have to use a computer. And that's not our goal: computers <em>are</em> more efficient. Filing your taxes online is better than doing them with a pen.<sup><a href="#user-content-fn-parking-meter" id="user-content-fnref-parking-meter" data-footnote-ref="" aria-describedby="footnote-label" class="footnote">1</a></sup></p>
<p>Our mission is to make it so that when she sits down in front of her computer, it is with a sense of calm, not dread. We want her to be able to find her stuff with more confidence, and less stress.</p>
<h2 id="values">Values</h2>
<blockquote>
<p><em>How will we behave while we do it?</em></p>
</blockquote>
<p>Johnny.Decimal is two humans: Johnny and his partner Lucy. We have no desire to grow. Becoming a big corporation wouldn't make us happy. We quit our jobs to do this <em>because</em> we love it; if we stop loving it, then what was the point?</p>
<p>This makes us a deeply 'Personal Business'.<sup><a href="#user-content-fn-personal" id="user-content-fnref-personal" data-footnote-ref="" aria-describedby="footnote-label" class="footnote">2</a></sup> You're dealing <em>with us</em>, and we with you.</p>
<p>We love the satisfaction that comes from helping an individual to be more organised. We love our community. We love the sense of worth that comes from creating something good using our own brains.</p>
<p>We don't seek to be incredibly good 'at business'. We don't follow the same old (dark) patterns, the same old (sleazy) techniques. Surely this means we earn less than we could, that we remain smaller than we might otherwise have grown. We're okay with that.</p>
<p>Because we, personally, seek something simple: we'd like to be able to buy a house and have chickens in the back yard. We think we can achieve that by making good things that people like, and selling them for an honest price. Let us know how we're doing.</p>
<h3 id="your-values">Your values</h3>
<blockquote>
<p><em>How would we like you to behave towards us?</em></p>
</blockquote>
<p>Company values statements typically don't turn it around to face the customer. But this is our company so we'll do whatever we like. ;-)</p>
<p>I spoke above about how we're proud to be a 'Personal Business'. But please remember that we are <em>still a business</em>. This is how we earn our living.</p>
<p>There is a curious behaviour that I have observed over the years.</p>
<ol>
<li>Everyone seeks to escape 'the rat race'. This is idolised as the highest form of being: to quit one's job, to 'go indie'.</li>
<li>So one quits one's job and 'goes indie', forfeiting the steady wage.</li>
<li>Now 'a creator', one needs to sell something in order to pay the rent and eat. (Capitalism! Who knew?)</li>
<li>People react to this 'sell-out'. How dare you sell the product of your mind? Information should be free!</li>
</ol>
<p>My ask of you is this: notice this reaction in your own mind. <strong>Be charitable in your assumptions</strong>.<sup><a href="#user-content-fn-hanlon" id="user-content-fnref-hanlon" data-footnote-ref="" aria-describedby="footnote-label" class="footnote">3</a></sup> If in doubt, ask the individual before posting about it on social media. We all need to earn money. You might do it by going to work. We do it by selling stuff online.</p>
<div data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-parking-meter">
<p>We're yet to be sold on the utility of an app over coins when paying for parking. <a href="#user-content-fnref-parking-meter" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref footnoteBackLink">↩</a></p>
</li>
<li id="user-content-fn-personal">
<p><a href="https://www.are.na/editorial/personal-business">Are.na / Personal Business by Charles Broskoski</a>. It's a great article, please read it. <a href="#user-content-fnref-personal" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref footnoteBackLink">↩</a></p>
</li>
<li id="user-content-fn-hanlon">
<p><a href="https://en.wikipedia.org/wiki/Hanlon's_razor">Hanlon's razor</a> providing a useful heuristic: "Never attribute to malice that which is adequately explained by stupidity." <a href="#user-content-fnref-hanlon" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref footnoteBackLink">↩</a></p>
</li>
</ol>
</div>Finished reading Kiosk Kingdom - Molly White's activity feed6a4c56646337b1f9eb5113992026-07-07T01:28:47.000Z<article class="entry h-entry hentry"><header><div class="description">Finished reading: </div></header><div class="content e-content"><div class="book h-entry hentry"><a class="book-cover-link" href="https://www.mollywhite.net/reading/books?search=Kiosk%20Kingdom"><img class="u-photo book-cover" src="https://m.media-amazon.com/images/S/compressed.photo.goodreads.com/books/1751370683i/237735252.jpg" alt="Cover image of Kiosk Kingdom" style="max-width: 300px;"/></a><div class="book-details"><div class="top"><div class="series-info"><i>Discount Dan's Backroom Bargains</i> series, book <span class="series-number">3</span>. </div><div class="title-and-byline"><div class="title"><i class="p-name">Kiosk Kingdom</i> </div><div class="byline">by <span class="p-author h-card">James A. Hunter</span>. </div></div><div class="book-info">Published <time class="dt-published published" datetime="2026-03-31">March 31, 2026</time>. 680 pages. </div></div><div class="bottom"><div class="reading-info"><div class="reading-dates"> Started <time class="dt-accessed accessed" datetime="2026-06-25">June 25, 2026</time>; completed July 6, 2026. </div></div></div></div></div><img src="https://www.mollywhite.net/assets/images/placeholder_social.png" alt="Illustration of Molly White sitting and typing on a laptop, on a purple background with 'Molly White' in white serif." style="display: none;"/></div><footer class="footer"><div class="flex-row post-meta"><div class="timestamp">Posted: <time class="dt-published" datetime="2026-07-07T01:28:47+00:00" title="July 7, 2026 at 1:28 AM UTC">July 7, 2026 at 1:28 AM UTC</time>. </div></div><div class="bottomRow"><div class="tags">Tagged: <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=fantasy" title="See all books tagged "fantasy"" rel="category tag">fantasy</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=humor" title="See all books tagged "humor"" rel="category tag">humor</a>, <a class="tag p-category" href="https://www.mollywhite.net/reading/books?tags=litrpg" title="See all books tagged "litRPG"" rel="category tag">litRPG</a>. </div></div></footer></article>