<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-CA">
    <title>nove.dev</title>
    <subtitle>devon&#39;s personal website</subtitle>
    <link rel="self" type="application/atom+xml" href="https://nove.dev/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://nove.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-23T21:30:00-07:00</updated>
    <id>https://nove.dev/atom.xml</id>
    <entry xml:lang="en-CA">
        <title>katamari architecture</title>
        <published>2026-09-23T21:30:00-07:00</published>
        <updated>2026-09-23T21:30:00-07:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/katamari-architecture/"/>
        <id>https://nove.dev/blog/katamari-architecture/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/katamari-architecture/">&lt;p&gt;&lt;em&gt;or, how to build a star out of mud&lt;/em&gt;&lt;/p&gt;
&lt;iframe src=&quot;https://archive.org/embed/KatamariFortissimoDamacy?playlist=1&amp;list_height=15&quot; width=&quot;500&quot; height=&quot;370&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;true&quot; mozallowfullscreen=&quot;true&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;User &lt;code&gt;marginalia&lt;/code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;https://nove.dev/blog/katamari-architecture/#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; &lt;a rel=&quot;external&quot; href=&quot;https://lobste.rs/c/fjedew&quot;&gt;on lobste.rs compared&lt;/a&gt; the output of poorly-directed software development LLM agents to the &quot;katamari&quot; from &lt;em&gt;Katamari Damacy&lt;/em&gt;: a video game in which you roll a clump of miscellaneous objects around, sticking everything you can find to the outside. It&#39;s an apt comparison; agentic development tends towards feature addition without attention to composition - they take the shortest path to accomplish the prompt. It has all the worst qualities of an underpaid and short-on-time human engineer. However, I think the analogy does a disservice to &lt;em&gt;Katamari&lt;/em&gt;! The spirit clod is carefully crafted (algorithmically, sure, but the algorithm was carefully crafted) to &lt;em&gt;appear&lt;/em&gt; thrown-together and unplanned, but the method by which they made the ball naturally round has enough complexity that they thought it warranted a &lt;a rel=&quot;external&quot; href=&quot;https://worldwide.espacenet.com/textdoc?DB=EPODOC&amp;amp;IDX=US7402104&quot;&gt;patent&lt;/a&gt;. By contrast, LLMs don&#39;t have the sense required to determine how to properly add whatever new feature their prompter desires, it&#39;s just stuck on at random (modulo a probability distribution). Despite that, katamari architecture is a catchy-enough buzzword that I hope it &quot;sticks&quot; around!&lt;/p&gt;
&lt;p&gt;Katamari architecture is here, but it&#39;s not a hopeless problem. Let&#39;s see if we can learn from prior work.&lt;/p&gt;
&lt;p&gt;The obvious comparison is the &lt;a rel=&quot;external&quot; href=&quot;https://www.laputan.org/mud/&quot;&gt;Big Ball of Mud&lt;/a&gt; architecture. Foote and Yoder argue that several &quot;forces [...] conspire&quot; to create BBoMs - time, cost, experience, skill, visibility, complexity, and scale. Considering driving forces is a good way to understand a phenomenon: &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Straw_man#Steelmanning&quot;&gt;steelman&lt;/a&gt; &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/G._K._Chesterton#Chesterton&amp;#x27;s_Fence&quot;&gt;Chesterton&lt;/a&gt; before slandering his fence. LLMs of course run roughshod over the metaphor, since they send fences zipping across vast expanses for no intelligible reason, moving them around at random as they sycophantically make &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/On_Bullshit&quot;&gt;bullshit&lt;/a&gt; replies to your incredulous questions. But I digress; can you build a katamari from the same impulses as mudballs?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time&lt;/strong&gt;: LLMs have plenty of time. Ostensibly they can work far faster than any human developer, 24/7 and over weekends and holidays. Time is not the issue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost&lt;/strong&gt;: Many companies have unlimited token budgets, whence tokenmaxing. If LLMs were any good at architecture, cost would be no object. The entire pitch of LLMs is that they&#39;re cheaper than humans to do the same work; cost isn&#39;t the issue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Experience&lt;/strong&gt;: Frontier LLMs are trained on (more-or-less) the sum total of all software ever written, along with all books, blogs, and forum posts ever written. There is no architectural process that LLMs are unfamiliar with, even though the nature of the beast means LLMs don&#39;t bring up anything besides the middle-of-the-road, lowest-common-denominator ideas without being, uh, prompted. Experience isn&#39;t the issue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skill&lt;/strong&gt;: Debatable. LLMs exhibit inhumanly &quot;spiky&quot;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;https://nove.dev/blog/katamari-architecture/#fn-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; intelligence, similar to other automated systems. They&#39;re impossibly good at some tasks (underspecified search through a large corpus of text) and hilariously bad at others (any number of publicised LLM epic fails, e.g. &lt;a rel=&quot;external&quot; href=&quot;https://techcrunch.com/2024/08/27/why-ai-cant-spell-strawberry/&quot;&gt;strawberry syndrome&lt;/a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https://www.reddit.com/r/PromptEngineering/comments/1r9bxx9/i_asked_5_popular_ai_models_the_now_viral/&quot;&gt;car-wash transportation&lt;/a&gt;, considering a vending machine &lt;a rel=&quot;external&quot; href=&quot;https://arxiv.org/html/2502.15840v1#S3.T4.4.9&quot;&gt;metaphysically impossible&lt;/a&gt;). As anyone who has to review LLM output for a living knows, the mistakes they make are not the same mistakes a human would make, and they&#39;re much harder to spot. Lack of skill is probably contributing to katamari architecture.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visibility&lt;/strong&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;https://nove.dev/blog/katamari-architecture/#fn-3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;: LLMs excel at generating vast swaths of code as far as the eye can see - which is part of the problem. No one is going to perform a close reading of a +6,000/-400 sloc PR - it&#39;s exhausting, and it&#39;s not going to change anything. The more LLM-generated a codebase, the worse visibility becomes. Andrej Karpathy &lt;a rel=&quot;external&quot; href=&quot;https://x.com/karpathy/status/1886192184808149383&quot;&gt;doesn&#39;t even read the code anymore&lt;/a&gt;. As Foote and Yoder put it, &quot;[i]f the system works, and it can be shipped, who cares what it looks like on the inside?&quot; That&#39;s the mantra of the modern vibecoder to a T. Just &lt;a rel=&quot;external&quot; href=&quot;https://arstechnica.com/ai/2026/04/research-finds-ai-users-scarily-willing-to-surrender-their-cognition-to-llms/&quot;&gt;surrender your cognition&lt;/a&gt;, embrace the clod!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: Most software has quite little &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Essential_complexity&quot;&gt;essential complexity&lt;/a&gt;, and at this scale &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Conway%27s_law&quot;&gt;Conway&#39;s law&lt;/a&gt; isn&#39;t relevant. Complexity may explain some BBoMs, but not the LLM-generated katamaris. I imagine a plurality of truly complex domains still have mostly &lt;a rel=&quot;external&quot; href=&quot;https://github.com/tigerbeetle/tigerbeetle/blob/47aeb2212a255273dda508288412e537d11e4b7c/src/tidy.zig#L1352&quot;&gt;hand-authored&lt;/a&gt; software, though it&#39;s a downward spiral at this point.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Change&lt;/strong&gt;: Human effort is a natural brake on the pace of change. Automatic coding accelerates change; LLMs make implementing a new change as easy as requesting it (with some rather heavy asterisks). Unlike human change, though, LLM-effected change tends to agglomerate onto the existing architecture (such as it is) rather than cut through the heart. A heavily LLM-affected katamari codebase often has a well-designed (human-designed, typically) core, obscured by layers of stylized household objects. An agent may decide to redesign the entire system, but rarely does it have the wherewithal; a redesign or rewrite is rightly feared by software artisans as complex, painful, and interminable. LLMs going for a redesign on their own are doomed to failure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scale&lt;/strong&gt;: Foote and Yoder&#39;s point (unless I&#39;ve misunderstood - the original is a little unclear to me) is that otherwise-skilled designers struggle to find elegance when faced with massive projects. I don&#39;t find this applies to agents all that well, they have mediocre performance even in the small. They don&#39;t get any better at working at a large scale, though.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Context compacted&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The main contributors from this list are skill, visibility, and change. LLMs are simply not very good at writing code relative to a skilled human, they&#39;re a whole new level of invisible code, and they axe the aerodynamic drag that keeps otherwise-muddy projects from collapsing into slop, ten 15,000 sloc PRs at a time.&lt;/p&gt;
&lt;p&gt;The visibility one is getting stuck in my craw. It wasn&#39;t bad enough that users couldn&#39;t see the horrible mud inside the application, now not even the developers are reading the code? we&#39;re so cooked chat&lt;/p&gt;
&lt;h3 id=&quot;what-is-to-be-done&quot;&gt;what is to be done?&lt;/h3&gt;
&lt;p&gt;LLMs are the accelerationist dream realized. Burn the coal, poison the well, kill the open web, hack the planet (starting with the rainforests). Weed out anyone with &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/AI-induced_psychosis&quot;&gt;latent schizophrenic tendencies&lt;/a&gt;. Obsolete trust. Flood the internet with &lt;a rel=&quot;external&quot; href=&quot;https://www.theguardian.com/technology/2026/sep/03/elon-musk-ai-grok-child-porn-lawsuit&quot;&gt;the unspeakable&lt;/a&gt;. Hope we come out the other side with infinite renewable energy, infinite compute, secure and performant software, abolished copyright and universal leisure. Cure all the diseases while we&#39;re at it. My anarchist utopia sure isn&#39;t going to happen as long as the billionaires hold the keys, though. If &lt;a rel=&quot;external&quot; href=&quot;https://jyn.dev/tokens-too-cheap-to-meter/&quot;&gt;jyn&lt;/a&gt; has any idea what they&#39;re talking about, we&#39;ll all have Astra-class models on our phones in a few years. Seems unlikely on the face of it.&lt;/p&gt;
&lt;p&gt;Hard though it may be to believe, I&#39;m no doomer. Vibecoders are way off, but it&#39;s &lt;a rel=&quot;external&quot; href=&quot;https://rfd.shared.oxide.computer/rfd/0576&quot;&gt;apparently&lt;/a&gt; possible to use these accursed orbs to build better software. I also don&#39;t claim to have a magic spell capable of bending the cthonic entities to our wills, but non-generative applications have the most promise. LLMs are &lt;a rel=&quot;external&quot; href=&quot;https://daniel.haxx.se/blog/2026/04/30/approaching-zero-bugs/&quot;&gt;evidently capable&lt;/a&gt; of finding legitimate bugs in carefully written code. Like fuzzing, it burns oodles of compute for this privilege; like fuzzing, hyperscalers are happy to send some &lt;del&gt;alms&lt;/del&gt; free compute to keep their pet OSS debugged.&lt;/p&gt;
&lt;p&gt;One &lt;a rel=&quot;external&quot; href=&quot;https://github.com/hawkw/mycelium/commit/b77e854bcbbe7c64f644e4c6ceeaebb74c80c79a&quot;&gt;idea I&#39;ve seen floated&lt;/a&gt; is that of an arms race between slopmeisters and software maintainers: &quot;you cannot use LLMs to contribute to this codebase, unless I can&#39;t tell that you used an LLM.&quot; I like this - it gives overburdened maintainers carte blanche to send any sloppy PRs to the shadow realm, for one, and in Eliza&#39;s words, &quot;the act of rewriting the model-generated code to not Look Like That forces the person who generated it to actually read and understand it thoroughly.&quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Foote and Yoder eventually conclude that BBoMs are a cynically optimal choice - software changes so rapidly under our feet that &quot;expedient, slash-and-burn, disposable programming is, in fact, a state-of-the-art strategy&quot;. I disagree with them, and I assert that katamari architecture is no better. BBoM and katamari architectures are coping mechanisms, wrought from the trauma of disillusioned practitioners being compelled to deliver endless vanity features while blowing past delivery&#39;s cosmetic deadlines. Software ate the world, and now it&#39;s &lt;a rel=&quot;external&quot; href=&quot;https://graveface.bandcamp.com/album/eating-us&quot;&gt;eating us&lt;/a&gt;. We don&#39;t need damn-the-torpedos full-throttle break-neck speed, we need care and attention.&lt;/p&gt;
&lt;p&gt;I want smaller software with &lt;em&gt;less&lt;/em&gt; bugs made by people who are paid more to work less&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-4-1&quot;&gt;&lt;a href=&quot;https://nove.dev/blog/katamari-architecture/#fn-4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; and &lt;a rel=&quot;external&quot; href=&quot;https://x.com/Jordan_Mallory/status/1277483756245442566?s=20&quot;&gt;I&#39;m not kidding&lt;/a&gt;!&lt;/p&gt;
&lt;hr /&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Author of the excellent smallweb search engine &lt;a rel=&quot;external&quot; href=&quot;https://marginalia-search.com&quot;&gt;marginalia&lt;/a&gt; &lt;a href=&quot;https://nove.dev/blog/katamari-architecture/#fr-1-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;Spikes are relative to &quot;human standard&quot;, which means neurodivergence (especially autism and ADHD) is often classed as spiky. In no way am I describing LLM intelligence as akin to autistic intelligence - the spikes are not aligned. There&#39;s only one way to be normal, but a variety of ways to be abnormal. &lt;a href=&quot;https://nove.dev/blog/katamari-architecture/#fr-2-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;A deeper visibility problem, that doesn&#39;t fit with the rest of this polemic - LLMs are more-or-less black boxes (notwithstanding some &lt;a rel=&quot;external&quot; href=&quot;https://www.anthropic.com/news/golden-gate-claude&quot;&gt;fascinating attempted brain surgery&lt;/a&gt;). We have no idea what&#39;s going on inside there. Explainable AI is as much a pipe dream as it was in &lt;a rel=&quot;external&quot; href=&quot;https://archive.org/details/intelligenttutor0000unse/page/52/mode/2up?q=SOPHIE&quot;&gt;SOPHIE&lt;/a&gt;&#39;s (&lt;em&gt;&lt;a rel=&quot;external&quot; href=&quot;https://nmbrs.bandcamp.com/album/product-2015&quot;&gt;recommended listening&lt;/a&gt;&lt;/em&gt;) era. &lt;a href=&quot;https://nove.dev/blog/katamari-architecture/#fr-3-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;Worker-owned co-ops might help. &lt;a href=&quot;https://nove.dev/blog/katamari-architecture/#fr-4-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
    </entry>
    <entry xml:lang="en-CA">
        <title>how to not fall for scams in the age of AI</title>
        <published>2026-09-10T10:40:00-07:00</published>
        <updated>2026-09-10T10:40:00-07:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/scams/"/>
        <id>https://nove.dev/blog/scams/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/scams/">&lt;p&gt;it&#39;s now roughly free to send a personalized, grammatically-perfect email from an account that seems to belong to a human. gone are the days where princes from a country on the other side of the world would drop apostrophes when trying to disburse millions of dollars to internet strangers. the most suspicious emails and texts we receive on a regular basis are legitimate communications from delivery companies attempting to coerce us to pay them for tariff paperwork. the old world is dying, and the new world struggles to be born.&lt;/p&gt;
&lt;p&gt;the best way to avoid losing all your money is to stay calm in the face of uncertainty and fear. the second best way is to establish an independent mode of communication. the third best way is to be skeptical of too-good-to-be-true offers.&lt;/p&gt;
&lt;p&gt;in general, emails and texts can be ignored for a few hours or a day without much consequence. that&#39;s plenty of time to come back down to your emotional baseline.&lt;/p&gt;
&lt;p&gt;if you&#39;re contacted by someone claiming to be your bank or credit card provider, hang up. there should be a phone number on the back of your card; call that number, wait in line, and tell the nice receptionist what happened. if there is really something happening, they will know about it; if not, you&#39;ve avoided being scammed and can feel glad about your safe practices. the same goes for a delivery company, cloud storage provider, internet provider, and whoever else. hang up / close the email, google the name of the company, and contact them directly. if you don&#39;t recognize the company, you can generally ignore it.&lt;/p&gt;
&lt;p&gt;clicking on a link is very safe, browsers like chrome, firefox, and safari put immense effort into making sure of that. the main danger is that you are tricked by the webpage pointed to by that link - maybe it looks like your bank and asks for your password, maybe it says you have malware and asks you to run a program, maybe it looks like a two-factor authentication or anti-bot captcha. it takes technical savvy and alertness to discern a real webpage from a scam. it helps to use a password manager with autofill - if your password doesn&#39;t autofill, it might not be safe. if you&#39;re uncertain about something, it&#39;s always best to contact someone you trust that&#39;s good with computers. they&#39;d much rather help you out than have you fall for a scam.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en-CA">
        <title>what is to be done about web hosting in 2026?</title>
        <published>2026-09-03T21:40:00-07:00</published>
        <updated>2026-09-03T21:40:00-07:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/hosting/"/>
        <id>https://nove.dev/blog/hosting/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/hosting/">&lt;p&gt;so far, my web infrastructure has been mostly hosted on cloudflare. they offer a reliable, feature-rich, and fast free tier. however, i&#39;ve been gradually souring on their business practices and general m.o. as a company. the question is, what alternatives exist? i&#39;m not opposed to paying a nominal fee if i have to (like, maybe $5/mo in total?), but my needs are so modest that i&#39;d really prefer not to if possible. i definitely do not want flexible billing, at least without a limit (that scared me off fastly). if there is the possibility of waking up to thousands in egress fees, i am not interested. i do pay google for cloud storage for my family, and i pay a friend to host a fediverse instance for me on her colo.&lt;/p&gt;
&lt;h2 id=&quot;static-site-hosting&quot;&gt;static site hosting&lt;/h2&gt;
&lt;p&gt;this service is free, or nearly so, at many service providers. i currently use cloudflare pages, i used to use github pages, there are options from vercel and others last i checked. none of those are interesting to me at this point. i like the idea of &lt;a rel=&quot;external&quot; href=&quot;https://grebedoc.dev&quot;&gt;grebedoc&lt;/a&gt; - community-driven web hosting led by an entity i&#39;ve been following for a long time and whose technical and personal opinions i usually am aligned with. however, it&#39;s far from battle-tested, and (imo) carries a higher risk of shutting down prematurely due solely to its recency. still, it&#39;s not like you&#39;re locked in to a static host. i like grebedoc.&lt;/p&gt;
&lt;h2 id=&quot;domain-registry&quot;&gt;domain registry&lt;/h2&gt;
&lt;p&gt;commodity web service that costs a pittance each year. i used to use google domains until they shuttered and i relocated to cloudflare. i have heard good things about porkbun, but honestly the name is distasteful to me and i&#39;d rather not. is njalla any good? more research here is needed.&lt;/p&gt;
&lt;h2 id=&quot;cronjob-compute&quot;&gt;cronjob compute&lt;/h2&gt;
&lt;p&gt;i have a service, &amp;lt;watertable.nove.dev&amp;gt;, that needs to wake up every night, crunch a bunch of time-series data in python, render and upload a website, and shutdown until tomorrow. so far i&#39;ve been using cloudflare pages&#39; build step to crunch the data and a cloudflare worker on a crontab to trigger the rebuild. it works quite well! this is not a service that i see offered for free from very many other providers. i could leech off of the ci compute of my git host (e.g. tangled, or just github actions (🤮)). i suppose i can self-host the crontab as well. i am somewhat averse to anything involving self-hosting for this particular service, though, because people that aren&#39;t me trust and rely on it for accurate and up-to-date information. maybe i will need to get some uptime monitoring service. is that free? hmm.&lt;/p&gt;
&lt;h2 id=&quot;email-routing&quot;&gt;email routing&lt;/h2&gt;
&lt;p&gt;my email is hosted on gmail, and that&#39;s not likely to change any time soon. i have been using &lt;code&gt;&amp;lt;wildcard&amp;gt;&lt;/code&gt;, at, &lt;code&gt;&amp;lt;my.domain&amp;gt;&lt;/code&gt; (obfuscated in a futile attempt to ward off scrapers) email addresses for a while, though, so i need to keep a wildcard redirect / mx record, or whatever, plus all the dkim/spf/dmarc nonsense. not everyone does this for free, as far as i know. i used to know all the details of email. i should do some more work on our hobby smtp server :)&lt;/p&gt;
&lt;h2 id=&quot;call-to-action&quot;&gt;call to action&lt;/h2&gt;
&lt;p&gt;what do you use for these? do you know any good options here? do you host some of these yourself? please let me know! i have a wildcard email record on this domain and love getting emails from humans :)&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en-CA">
        <title>advent of code 2025</title>
        <published>2025-12-01T12:06:00-08:00</published>
        <updated>2025-12-01T12:06:00-08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/aoc-2025/"/>
        <id>https://nove.dev/blog/aoc-2025/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/aoc-2025/">&lt;p&gt;last year i never did any aoc, though i&#39;ve been &lt;a rel=&quot;external&quot; href=&quot;https://tangled.org/nove.dev/aoc-2024/&quot;&gt;retroactively working&lt;/a&gt; on some of the problems. this year i&#39;ll do it!&lt;/p&gt;
&lt;p&gt;i always aspire to complete the whole month and get stymied partway through. hopefully this year will be different :) i will show more persistence and do more background research on the compsci fundamentals; maybe i&#39;ll write some abstracted algorithms or data structures to do frequent tasks. the recommended reading below is mostly for myself!&lt;/p&gt;
&lt;p&gt;i&#39;m putting &lt;a rel=&quot;external&quot; href=&quot;https://tangled.org/nove.dev/aoc-2025/&quot;&gt;my solutions&lt;/a&gt; on tangled, writing in rust, using jujutsu for version control, and a nix flake for a dev environment. it&#39;s a good mix of low-friction while still using new tools that i want to be better at. plus, i don&#39;t use rust at work much anymore, so i need to keep the proverbial rust off.&lt;/p&gt;
&lt;p&gt;recommended reading:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://lobste.rs/c/6lunsz/&quot;&gt;this comment&lt;/a&gt; on &lt;a rel=&quot;external&quot; href=&quot;https://lobste.rs/&quot;&gt;lobste.rs&lt;/a&gt;, which discusses strategies if you find yourself stuck, common data structurs &amp;amp; algorithms, and textbooks to read for more of a theory background&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://elly.town/d/blog/2025-09-01-advent-of-code-500.html&quot;&gt;elly&#39;s post&lt;/a&gt;, elly&#39;s solved every aoc out there and has good advice&lt;/li&gt;
&lt;/ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en-CA">
        <title>thoughts on the latest cloudflare outage</title>
        <published>2025-11-21T20:06:00-08:00</published>
        <updated>2025-11-21T20:06:00-08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/cloudflare/"/>
        <id>https://nove.dev/blog/cloudflare/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/cloudflare/">&lt;p&gt;against my best instincts, i will put forward my opinion on the recent cloudflare outage. you should probably read their &lt;a rel=&quot;external&quot; href=&quot;https://blog.cloudflare.com/18-november-2025-outage/&quot;&gt;postmortem&lt;/a&gt; for context.&lt;/p&gt;
&lt;h2 id=&quot;intro-and-background&quot;&gt;intro and background&lt;/h2&gt;
&lt;p&gt;tl;dr is that a quarter of the internet went down because a database change caused oversized config files to be propagated to a critical component of their core proxy. this component used a fixed amount of preallocated memory as an optimization, and nothing validated the size of the config it was parsing. when the oversized config was loaded, the application crashed, which translated into an http 500 server error, which blocked all traffic attempting to traverse that component. in other words:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CAD3F5; background-color: #24273A;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;cloudflare:&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; i would like to parse dynamic config generated by an external service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;        me:&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; fair enough&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;cloudflare:&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; i would like to restrict the size of this config, for performance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;        me:&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; fair enough&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;        me:&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; what will you do if the config is too big?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;cloudflare:&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; die instantly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;        me:&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; ah.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;spooky-scary-sloppy-rust-code&quot;&gt;spooky scary sloppy rust code&lt;/h2&gt;
&lt;p&gt;the snippet of code provided in the postmortem is as follows:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CAD3F5; background-color: #24273A;&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;pub fn&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt; fetch_features&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;    &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;color: #ED8796;&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #EE99A0;&quot;&gt;    input&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;dyn&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; BotsInput&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #EE99A0;&quot;&gt;    features&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; Features&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;color: #91D7E3;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(), (&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt;ErrorFlags&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt; i32&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #91D7E3;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    features&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span&gt;checksum &lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;&amp;amp;=&lt;/span&gt;&lt;span style=&quot;color: #F5A97F;&quot;&gt; 0xFFFF_FFFF_0000_0000&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    features&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span&gt;checksum &lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;|=&lt;/span&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt; u64&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ED8796;&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;&quot;&gt;checksum&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; (&lt;/span&gt;&lt;span&gt;feature_values&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&lt;/span&gt;&lt;span&gt; features&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;        .&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;append_with_names&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #ED8796;&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;&quot;&gt;feature_names&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;        .&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the problematic part is that last line: &lt;code&gt;.unwrap()&lt;/code&gt;. in rust, errors are handled using sum types, namely, &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt;. this &lt;code&gt;Result&lt;/code&gt; object can then be dealt with in various ways: either explicitly with &lt;code&gt;match&lt;/code&gt;, &lt;code&gt;if let&lt;/code&gt;, or &lt;code&gt;let ... else&lt;/code&gt;; automatically with &lt;code&gt;?&lt;/code&gt; or &lt;code&gt;.unwrap_or_else()&lt;/code&gt;; dangerously with &lt;code&gt;.unwrap()&lt;/code&gt;; or &lt;code&gt;unsafe&lt;/code&gt;ly with &lt;code&gt;.unwrap_unchecked()&lt;/code&gt;. here&#39;s how each would have looked; don&#39;t mind the owl references, we&#39;ll get to it:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CAD3F5; background-color: #24273A;&quot; &gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//we don&amp;#39;t know the actual return type of .append_with_names(), &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//so this is a guesstimate:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;let&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;color: #91D7E3;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt;Vec&lt;/span&gt;&lt;span style=&quot;color: #91D7E3;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt;FeatureValues&lt;/span&gt;&lt;span style=&quot;color: #91D7E3;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; Unknown&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;),&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; AppendError&lt;/span&gt;&lt;span style=&quot;color: #91D7E3;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;    =&lt;/span&gt;&lt;span&gt; features&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;append_with_names&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #ED8796;&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;&quot;&gt;feature_names&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//handle the error directly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;match&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt;    Ok&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;((&lt;/span&gt;&lt;span&gt;feature_values&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt; /*do whatever you needed to do here*/&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt;    Err&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;        log_error!&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; &amp;quot;failed to append features when loading config&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;        //draw the rest of the owl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//find a safe default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; (&lt;/span&gt;&lt;span&gt;feature_values&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;unwrap_or_else&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;|&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;    log_error!&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt; &amp;quot;failed to append features when loading config&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;vec!&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;[],&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; Default&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt; //draw the rest of the owl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//bubble it up - let the caller draw the rest of the owl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;((&lt;/span&gt;&lt;span&gt;feature_values&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;    log_error!&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt;&amp;quot;failed to append features when loading config&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt; Err&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt;ErrorFlags&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #EED49F;font-style: italic;&quot;&gt;AppendError&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #F5A97F;&quot;&gt; 120&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;))&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;    //who knows what this error return should be&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//another way to bubble it up, more conveniently but without a local log &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//(assuming the error type is convertible)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; (&lt;/span&gt;&lt;span&gt;feature_values&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//the bare minimum - cloudflare&amp;#39;s actual solution.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//crash the program if you can&amp;#39;t append&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; (&lt;/span&gt;&lt;span&gt;feature_values&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//more or less equivalent to the above, with slightly better debuggability&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; (&lt;/span&gt;&lt;span&gt;feature_values&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;expect&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A6DA95;&quot;&gt;    &amp;quot;there should be a max of 200 feature values&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//abdicate all responsibility. perform undefined behaviour if you can&amp;#39;t append. &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//here there be memory corruption. summon the nasal demons.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;font-style: italic;&quot;&gt;//thankfully cloudflare had the sense not to do this&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; (&lt;/span&gt;&lt;span&gt;feature_values&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #C6A0F6;&quot;&gt; unsafe&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    res&lt;/span&gt;&lt;span style=&quot;color: #8BD5CA;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8AADF4;font-style: italic;&quot;&gt;unwrap_unchecked&lt;/span&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #939AB7;&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;what-s-wrong-with-unwrapping&quot;&gt;what&#39;s wrong with unwrapping&lt;/h2&gt;
&lt;p&gt;unwraps are to be used in one of two&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-third-1&quot;&gt;&lt;a href=&quot;https://nove.dev/blog/cloudflare/#fn-third&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; scenarios:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;you do not care about your code very much. if it crashes, who cares&lt;/li&gt;
&lt;li&gt;the error is believed to be completely impossible. there is an invariant being upheld that rust&#39;s type system is insufficiently smart to prove. if the value is an error, something has gone catastrophically wrong and no assumptions can be made about the state of the program. the only safe response is to panic, unwind the stack and kill the entire thread. we can only pray that is enough.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;this unwrap falls in neither of these. cloudflare&#39;s core proxy is critical infrastructure and thus must make every effort not to crash, eliminating the first point. the second is where cloudflare-positive discourse seems to have placed them - the engineer and code reviewer must have believed it impossible to fail here. i disagree - in a situation where you are parsing input provided from an external system, generated by a database, across a network boundary, no assumptions can be made. operate as if it is, if not actively malicious, at least highly suspicious.&lt;/p&gt;
&lt;p&gt;cloudflare&#39;s core proxy code should probably have zero potential panics in it. this makes it more difficult to write rust, i understand that. if they must write panicking code, at the &lt;em&gt;very least&lt;/em&gt; it should have safety-style comments above each potential panic indicating why the engineer believes a panic is impossible.&lt;/p&gt;
&lt;p&gt;additionally, this component of the core proxy was a filter designed to keep llm scrapers and other (semi-)malicious bots from accessing a client site. in the event of a catastrophic failure like this, the component should &lt;em&gt;obviously&lt;/em&gt; fail open - bot management is not a reliable security boundary, and increasing load / visibility is far superior to taking the website off the internet altogether. present one of those horrible little javascript challenges on each page load if you must (i&#39;m thinking of ticket-sellers looking to avoid being bought out by bots), but don&#39;t break the web. different components have different threat models; i&#39;m sure e.g. their zero trust product would prefer failing closed.&lt;/p&gt;
&lt;h2 id=&quot;crux&quot;&gt;crux&lt;/h2&gt;
&lt;p&gt;the core of the issue is an unstated, unvalidated assumption - the config will never exceed 200 features. rust did its best to warn the coder about this issue; the coder responded by explicitly ignoring the concern, and this outage is the result. a sufficiently conscientious programmer and reviewer would have looked at this &lt;code&gt;Result&lt;/code&gt;, thought &quot;how might i handle this properly&quot;, and pursued a proper solution.&lt;/p&gt;
&lt;p&gt;now we finally return to &quot;draw the rest of the owl&quot;; it is not obvious what this solution should have been. i have several ideas: there could have been a validator in the config generator or distributor, plus a &lt;code&gt;//SAFETY&lt;/code&gt; comment immediately before this unwrap; that would have prevented the outage. i&#39;m hesitant about this, though - if the validator fails, we&#39;re back where we started. the solution could have also been a configuration manager that stores past versions, so the proxy could revert to a previous known-good config in the event of a misconfiguration like this.&lt;/p&gt;
&lt;h2 id=&quot;how-i-would-have-fixed-this&quot;&gt;how i would have fixed this&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;configuration is about defining a point in multidimensional space&lt;/strong&gt;. this point is fed to your program to define its initial state and rules about how it handles input and output. if configuration fails, a critically important program should continue to work at all costs, in this case by statically choosing an acceptable default point in the state-space, inhabiting it, and logging a maximum-severity error message. ideally, such a message would trigger an alert and page an on-call engineer to fix the problem immediately, but until then, nothing is fundamentally broken. for this program, the sensible static default is &quot;allow every request through&quot;.&lt;/p&gt;
&lt;h2 id=&quot;postscriptum-response-to-this-is-rust-s-fault&quot;&gt;postscriptum - response to &quot;this is rust&#39;s fault&quot;&lt;/h2&gt;
&lt;p&gt;if this had been c, cloudflare would have failed to check the error code and proceeded to perform undefined behaviour. whee, memory safety cves! if this had been java, javascript, python, go, haskell, c#, kotlin, lisp, etc., this program would have been ripped out and rewritten in rust; if cloudflare is so memory-constrained as to only allow 200 entries in an array, a garbage-collected language would have been right out. if this had been c++, it would have thrown an unchecked exception, same as the panic, and the outage would have been exactly the same. maybe zig solves this; i haven&#39;t written any zig.&lt;/p&gt;
&lt;p&gt;rust is not a perfect language. the naming of &lt;code&gt;.unwrap()&lt;/code&gt; is suboptimal; error handling in tutorials and educational work is often brushed under the rug with it. maybe in rust 2.0, which will never happen, we can rename unwrap. until then, it is the professional responsibility of engineers, at least those who create programs which must have extremely high reliability, to understand the language in which they work and not litter their code with potential crashes.&lt;/p&gt;
&lt;hr /&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-third&quot;&gt;
&lt;p&gt;there is a third&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-fourth-1&quot;&gt;&lt;a href=&quot;https://nove.dev/blog/cloudflare/#fn-fourth&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;, false option: if you handle panics with &lt;a rel=&quot;external&quot; href=&quot;https://doc.rust-lang.org/std/panic/fn.catch_unwind.html&quot;&gt;&lt;code&gt;catch_unwind&lt;/code&gt;&lt;/a&gt; or a panic hook, and you will convert the panic into an error 500 or something. cloudflare probably had this, it&#39;s common in web frameworks. this is not something you want to rely on. panic catching is dangerous; if you panic within a panic (either in a &lt;code&gt;Drop&lt;/code&gt; implementation or the panic handler) it hard-aborts your program immediately. also, responding with a 500 is not actually the correct response in this case! as i said above, this filter should have failed open, not responded to every request with a 500. listen to the rust documentation: &quot;it is not recommended to use this [...] for a general try/catch mechanism&quot; &lt;a href=&quot;https://nove.dev/blog/cloudflare/#fr-third-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-fourth&quot;&gt;
&lt;p&gt;another, even less defensible idea: you are allowed to panic if there is no sensible way of responding to such an error. i disagree with this - in a webserver, you want to respond to the client no matter what; in a user-driven app with a gui, tui, or cli, splatting a panic stacktrace is not a friendly user experience; in a library you should &lt;em&gt;really&lt;/em&gt; never panic but always return some indication of failure, etc. &lt;a href=&quot;https://nove.dev/blog/cloudflare/#fr-fourth-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
    </entry>
    <entry xml:lang="en-CA">
        <title>on correctness</title>
        <published>2025-11-17T13:00:00-08:00</published>
        <updated>2025-11-17T13:00:00-08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/correctness/"/>
        <id>https://nove.dev/blog/correctness/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/correctness/">&lt;p&gt;correctness should be the baseline in software. luckily, correctness is a mathematical property of an algorithm, and thus we can use computers to help humans build correct software. millions of lines of code have been written for the express purpose of helping humans prove subsets of correctness. i&#39;m thinking of (ranked by how much assurance they provide, in decreasing order): formal verification, type systems, linters, property testing, unit testing, fuzzers, autoformatters, and syntax highlighters.&lt;/p&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;formal verification is the highest standard of correct software. i do not have direct experience with it. to my understanding, it converts many programming errors into much fewer specification errors, which tend to be easier to solve.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;type systems, when implemented kindly, are the best tool for correctness. they enable local reasoning, tooling support, invariants. when implemented with the sharp edge against the programmer, the programmer learns to hate them. the difference between a kind type system and a sharp type system is how the programmer feels about the type system. if the programmer writhes in its grasp, flailing against the oppressive all-seeing eye of &quot;computer says no&quot;, the type system is not helping achieve correct software. if the programmer uses the type system as a tool, sketching their software out in broad strokes, knowing with certainty the potential states and being assured of the correctness of composition, it&#39;s good.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;i have a distaste for gradual typing systems, as the flow goes something like this: working, highly dynamic program -&amp;gt; overlaid type system incorrectly proclaims incorrectness -&amp;gt; programmer develops hatred for type systems&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;linters are a good way to soften the blow of a compiler error. moving from &quot;computer says no&quot; to &quot;computer says you&#39;re wrong, but here&#39;s an escape hatch labelled &#39;do not use&#39;&quot;. the downside of this approach is obvious, however: programmers are creatures of infinite creativity and chaotic alignments. when deadlines are imposed, the programmer is burnt out, or years of useless lints have jaded their saliency checker, lints are ignored and software is built incorrectly. equally, escape hatches allow lint writers to be more careless about false positives, pushing the vicious cycle one step further&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;property testing is interesting to me. i have used it but lightly, and never in anger. from my perspective, property testing gives you 80% of the assurance of formal verification with 20% of the effort. of course, an 80% correct program is rarely good enough. the core conceit is to formalize properties about your functions, formalize ways of generating input to said functions, and machine-checking the whole shebang.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;i have described unit testing suites as brittle exoskeletons attached to the nerves of a program. with the slightest twitch, a change to a program can shatter its exoskeleton to dust while self-inflicting great pain. the result of this, and thus the purpose of unit testing systems, is to disincentivise change of any kind. have fun migrating off .net 6.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;however, i have had the immense displeasure of refactoring a complicated program with no test suite whatsoever. combined with the total lack of documentation, &lt;a rel=&quot;external&quot; href=&quot;https://www.hyrumslaw.com/&quot;&gt;hyrum&lt;/a&gt; ensured that any minor modification would break something with no warning. therefore, i consider unit testing to be something of a necessary evil, and keep hope that a better world is possible.&lt;/li&gt;
&lt;li&gt;property testing suffers from the same problem in theory, yet in practice the properties are sufficiently abstract as to allow for enough program movement so as to not atrophy.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fuzzers are a reduced form of property testing applied to an entire program, usually with some level of codepath-aware analysis to minimize breadth-first-search-itis. the exoskeleton is kept at a safe distance from the slithering muscles beneath, which allows for major refactors that don&#39;t change the basic api. however, they don&#39;t check correctness. fuzzers can root out memory safety bugs, edge case crashes, and input mishandling, for which they are invaluable, but a fuzzer on its own isn&#39;t good enough.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;autoformatters, like type systems, are best when they are human-focused and not impositional. an autoformatter offloads mental effort from the programmer by keeping a program in a consistent style - the writer doesn&#39;t have to fuss about indentation and the reader can load the program into their mental approximation without being distracted by a format different from the one they use. it serves the same purpose as typesetting rules at a scientific journal. the formatter has to be universally applied. it must be consistent and disrespect programmer intentions to be valuable, but its style must be smart enough to not cause anger.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;autoformatters can also catch errors themselves, usually by papering over language-level problems. &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Unreachable_code#goto_fail_bug&quot;&gt;goto fail&lt;/a&gt;, while indicative of a half-dozen problems with the c language (unreachable code is legal, if statements don&#39;t require braces, goto in general, rampant mutability, &lt;a rel=&quot;external&quot; href=&quot;https://joeduffyblog.com/2016/02/07/the-error-model/#error-codes&quot;&gt;error codes&lt;/a&gt;), would have nevertheless been caught by a human reviewer if the code was autoformatted.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;syntax highlighting instantly catches syntax-level errors without requiring a full compiler pass or linter run. it&#39;s the fastest feedback we have available - misspelled a keyword? it&#39;s the wrong colour, your brain &lt;em&gt;knows&lt;/em&gt; something&#39;s wrong before you can consciously respond to it. i consider consciousness a slow and error-prone&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-consciousness-1&quot;&gt;&lt;a href=&quot;https://nove.dev/blog/correctness/#fn-consciousness&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; method of cognition, and short-circuiting it lets you write better code faster.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-consciousness&quot;&gt;
&lt;p&gt;this requires some explanation. when you&#39;re doing your best work, you &quot;lose yourself&quot; in it. no one considers a self-conscious or self-aware coding style any good. our consciousness lies, makes up narratives, and generally runs interference. of course, preconscious cognition is much less sophisticated, and so conscious composition is indispensable. for a longer-form meditation on consciousness as a liability, try reading &lt;a rel=&quot;external&quot; href=&quot;https://www.rifters.com/real/Blindsight.htm&quot;&gt;blindsight&lt;/a&gt; &lt;a href=&quot;https://nove.dev/blog/correctness/#fr-consciousness-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
    </entry>
    <entry xml:lang="en-CA">
        <title>software engineers don&#39;t exist</title>
        <published>2025-11-14T21:10:00-08:00</published>
        <updated>2025-11-18T21:17:00-08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/engineering/"/>
        <id>https://nove.dev/blog/engineering/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/engineering/">&lt;p&gt;my employer calls me a software engineer. i disagree.&lt;/p&gt;
&lt;p&gt;i think software engineering is a misnomer, not because what we do is materially different from what engineers do, but because we lack the professional and legal institutions engineers have. when a software developer can refuse to write unsafe code, whistleblow to an oversight agency, and be free from fear of retribution, then they can call themselves an engineer. when the legally enshrined organization pairs new grads with experienced mentors, with whom they must work for multiple years before they receive a government-recognized certification, then we can call what we do engineering. when we base technical decisions on scientific data instead of vibes and shoddy undergraduate studies. when our field reads and understands our own history instead of chasing vc whims and riding bubbles.&lt;/p&gt;
&lt;p&gt;i spent a couple years in an engineering program at university. i have no misconceptions that &quot;real&quot; engineers are any more ethical than software developers. in my first year, we received a lecture on engineering ethics from a man who worked on weapons programs for the u.s. department of &quot;defense&quot;, which disillusioned me from the entire discipline. but i still believe a better world is possible, and until software stops killing people we need to move slow and correct things.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;update 2025-11-18: i recently encountered this article from the acm, whose area is rather relevant to the subject at hand. &lt;a rel=&quot;external&quot; href=&quot;https://cacm.acm.org/opinion/software-professionals-malpractice-law-and-codes-of-ethics/&quot;&gt;recommended reading&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;update 2026-01-19: found another &lt;a rel=&quot;external&quot; href=&quot;https://alexwennerberg.com/blog/2025-11-28-engineering.html&quot;&gt;recommended post&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;update 2026-01-19: i also like &lt;a rel=&quot;external&quot; href=&quot;https://bsky.app/profile/sunshowers.io/post/3mvyv7xykvc2h&quot;&gt;rain&#39;s take&lt;/a&gt;; just because we aren&#39;t engineers doesn&#39;t mean we shouldn&#39;t act like them, and our obsession with building our own tools should be cherished&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en-CA">
        <title>catalogue of personal computation</title>
        <published>2025-11-14T20:41:00-08:00</published>
        <updated>2025-11-14T20:41:00-08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/computer-catalogue/"/>
        <id>https://nove.dev/blog/computer-catalogue/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/computer-catalogue/">&lt;p&gt;my desktop is a decommissioned compute server that my old employer was giving away after they got acquired and the new parent pushed everything into aws. it has a 48-core threadripper and 256gb of ram, 128 of which is in a drawer of my desk because it makes my overclock unstable. it&#39;s wildly overkill 95% of the time, underpowered 10% of the time (single-core performance was never threadripper&#39;s strong suit, and the state of the art has gotten a lot better since zen 2), and very appreciated 5% of the time: i was repeatedly recompiling ffmpeg the other day and task manager claimed i hit 101% cpu usage. it runs windows because elden ring holds me hostage; all my development is done in a wsl2 vm running either nixos or arch. i think nixos solves more or less all linux problems and replaces them with nixos problems, which is a mixed blessing. i use lix instead of cppnix for ideological reasons.&lt;/p&gt;
&lt;p&gt;i have a pair of b&amp;amp;w passive bookshelf speakers and a b&amp;amp;w active subwoofer, which i power with a fosi audio v3 amp. i recommend all of these very highly; i listen to a lot of music on them. i plan to get a dac, headphone amp, maybe microphone setup someday.&lt;/p&gt;
&lt;p&gt;my home server is composed of extremely sketchy hardware, notwithstanding the redundant zfs storage pool. the side panel won&#39;t go back on ever since i swapped the motherboard for one with a hyper 212 evo, which is too tall for the micro-atx case. the power button hasn&#39;t worked for 5 years; i use a screwdriver to bridge the pins on the motherboard. two of the four hard drives are failing, which is why i have the other two. the psu fan failed in 2025, so i cannibalized my old gaming pc for its evga (rip) psu and swapped it in. honestly i&#39;m impressed that the 400w psu cooler master included with its bottom-of-the-line case in 2018 lasted 7 years without lighting on fire. the server&#39;s main purpose is to run the unifi controller, which i manage with a bizarrely bulletproof bash script, and act as an smb server. i haven&#39;t had any issues with the software in years. i ran freenas as a kid but got annoyed with freebsd software availability, then i ran truenas scale but got annoyed by the unfinished betaness of it all, so i gave up on semicustom distributions and installed ubuntu server lts.&lt;/p&gt;
&lt;p&gt;my personal laptop is a lenovo yoga i got in 2019 when i was starting my degree, for which it was perfect. it has a touch screen, stylus, and 360 degree hinge with an i7 and 8gb of ram. power use while sleeping is abysmal, performance is terrible when using modern software, 8gb of ram is no longer enough. it can still run wsl2 with arch and a text editor, so i try to use it mostly for that. the speakers and fingerprint reader do not work in linux. the drivers are not open source and no one has managed to reverse engineer them, otherwise i would have put arch on it years ago. eventually, i see myself getting a macbook air.&lt;/p&gt;
&lt;p&gt;my work laptop is a macbook pro 16&quot; with an m3 pro and 36gb of ram. battery life and performance are very good, though i think my desktop can still beat it in a multicore drag race.&lt;/p&gt;
&lt;p&gt;i have a raspberry pi collecting dust in the closet. i used to have an arm vm on oracle&#39;s free plan. it ran a minecraft server for a while, then the backend for a web toy i made, and nothing since they closed it for inactivity in 2024.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en-CA">
        <title>blogpost about static site generation</title>
        <published>2025-11-14T19:40:00-08:00</published>
        <updated>2025-11-14T19:40:00-08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nove.dev/blog/meta/"/>
        <id>https://nove.dev/blog/meta/</id>
        
        <content type="html" xml:base="https://nove.dev/blog/meta/">&lt;p&gt;as is tradition, now that i&#39;ve stripped my old website to the bones, my first post must be about the  technology that made the new website. if i am to follow in my priors&#39; footsteps, this will also be the last post on this blog. i endeavour to not.&lt;/p&gt;
&lt;p&gt;both this site and my old site use the zola static site generator. my old site was laden with plenty of custom css, unpopular ideas about fonts, and altogether too much self-importance. this current site uses the stock terminimal theme with no adjustments, so hopefully i can actually write posts instead of screwing around with css. &lt;s&gt;at least i&#39;ve kept the theme colour&lt;/s&gt; nope, green looks better.&lt;/p&gt;
&lt;details&gt;
    &lt;summary&gt;aside&lt;/summary&gt;
    &lt;p&gt;i originally used pure CMYK magenta, on the hubristic idea that one day my resume would be printed on a colour printer. i don&#39;t think that has ever happened, and it&#39;s weird for a computer professional to have a dead-trees-focused resume. it also was (is) too bombastic. after i&#39;m happy with this site, i&#39;ll rewrite my resume in typst with a basic theme. it&#39;ll be linked here, eventually.&lt;/p&gt;
    &lt;details&gt;
        &lt;summary&gt;aside aside&lt;/summary&gt;
        &lt;p&gt;i lightly wish terminimal had asides. i&#39;m not convinced they work on mobile, at all - it requires a certain width of reading area that mobile lacks completely. still, they work in a similar way to my brain. this is a nested aside, not that it renders that way. i&#39;m polyfilling with details tags. i wonder how i expect a doubly-nested aside to work&lt;/p&gt;
    &lt;/details&gt;
&lt;/details&gt;
&lt;p&gt;zola&#39;s pretty good, if a little obtuse with its sections-and-pages systematization. it could use better error messages, but it really didn&#39;t take too long to refamiliarize myself with after not touching it for years, and now it&#39;s mostly staying out of my way. i like the terminimal theme, partially from association with other blogs i respect. i appreciate the lack of javascript.&lt;/p&gt;
</content>
        
    </entry>
</feed>
