<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Lab notes — Danniel Hansel</title>
    <link>https://dannielhansel.app/blogs</link>
    <description>Essays, notes and tutorials by Danniel Hansel.</description>
    <language>en-us</language>
    <atom:link href="https://dannielhansel.app/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Delivering a lean digital product during the pandemic</title>
      <link>https://dannielhansel.app/blogs/how-to-deliver-a-lean-digital-product-with-limited-resources</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/how-to-deliver-a-lean-digital-product-with-limited-resources</guid>
      <pubDate>Tue, 20 Oct 2026 12:00:00 GMT</pubDate>
      <description>How I shipped online ordering for a Texas seafood restaurant during pandemic dine-in limits: a lean MVP, built solo with Gatsby, GloriaFood, Stripe and AWS.</description>
    </item>
    <item>
      <title>I built a small software factory. Here is how it works and where it failed</title>
      <link>https://dannielhansel.app/blogs/forty-seven-runs-through-my-software-factory</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/forty-seven-runs-through-my-software-factory</guid>
      <pubDate>Tue, 13 Oct 2026 12:00:00 GMT</pubDate>
      <description>How a planner, a builder and a set of deterministic gates take one written slice to a commit, measured over 47 runs, with what the gates caught and what they let through.</description>
    </item>
    <item>
      <title>What does it cost to turn on TypeScript's strictest flags?</title>
      <link>https://dannielhansel.app/blogs/three-compiler-flags-and-everything-they-touched</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/three-compiler-flags-and-everything-they-touched</guid>
      <pubDate>Tue, 13 Oct 2026 12:00:00 GMT</pubDate>
      <description>4,189 type errors against an estimate of 200, a plan rewritten three times, one code review an hour, and the count that turned out to be a floor.</description>
    </item>
    <item>
      <title>How a lint autofix can change what your tests check without failing one</title>
      <link>https://dannielhansel.app/blogs/a-lint-autofix-can-change-what-your-tests-check</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/a-lint-autofix-can-change-what-your-tests-check</guid>
      <pubDate>Sat, 10 Oct 2026 12:00:00 GMT</pubDate>
      <description>4,336 lint problems, one command, and the six things that command would have broken. What a count can tell you about a method, and what only running it can.</description>
    </item>
    <item>
      <title>We gave an AI assistant read-only access to our ops stack. Its best answer was 'I can't tell'</title>
      <link>https://dannielhansel.app/blogs/first-run-of-a-read-only-ops-mcp-server</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/first-run-of-a-read-only-ops-mcp-server</guid>
      <pubDate>Mon, 28 Sep 2026 12:00:00 GMT</pubDate>
      <description>A read-only ops server for AI assistants: two security bugs caught before its first run, and 288 zeros it refused to read as health.</description>
    </item>
    <item>
      <title>Our load test found a real bug, and briefly inflated our own stats</title>
      <link>https://dannielhansel.app/blogs/load-testing-production-with-synthetic-players</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/load-testing-production-with-synthetic-players</guid>
      <pubDate>Mon, 28 Sep 2026 12:00:00 GMT</pubDate>
      <description>Eight runs, four in production. Each fix exposed the next limit. The harness's own checks caught one of its six mistakes; the other five took a second count.</description>
    </item>
    <item>
      <title>A join that took 11 seconds, and the retry that locked players out</title>
      <link>https://dannielhansel.app/blogs/a-join-that-took-11-seconds</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/a-join-that-took-11-seconds</guid>
      <pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate>
      <description>5,297 timed joins, four over five seconds, and the rule that a slow join must finish because its answer carries the seat cookie.</description>
    </item>
    <item>
      <title>One database round trip was 17% of our median answer</title>
      <link>https://dannielhansel.app/blogs/benchmark-websocket-rooms-against-a-remote-database</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/benchmark-websocket-rooms-against-a-remote-database</guid>
      <pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate>
      <description>A latency benchmark of our Rust WebSocket rooms against a database 61-73 ms away, the confounds, and the A/B that found one more round trip.</description>
    </item>
    <item>
      <title>20 failures in one morning, and not one was caught by a unit test</title>
      <link>https://dannielhansel.app/blogs/evals-from-scars-beta-11-to-beta-12</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/evals-from-scars-beta-11-to-beta-12</guid>
      <pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate>
      <description>Twenty failures from one morning, what first caught each one, and the written checks with positive controls that our coding agents now run first.</description>
    </item>
    <item>
      <title>23 pull requests passed review. The branch they made had three bugs</title>
      <link>https://dannielhansel.app/blogs/review-the-whole-branch-not-only-each-pull-request</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/review-the-whole-branch-not-only-each-pull-request</guid>
      <pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate>
      <description>23 green per-PR reviews, one 563-file parent, and the three bugs that lived between the pull requests.</description>
    </item>
    <item>
      <title>42 write routes trusted SameSite=Lax, which trusts the whole site</title>
      <link>https://dannielhansel.app/blogs/samesite-lax-is-same-site-not-same-origin</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/samesite-lax-is-same-site-not-same-origin</guid>
      <pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate>
      <description>Why a Lax cookie plus a JSON route is not CSRF protection, how one request showed it, and the guard and scan that replaced it.</description>
    </item>
    <item>
      <title>Can two real-time services share one small VPS?</title>
      <link>https://dannielhansel.app/blogs/two-real-time-services-on-one-small-vps</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/two-real-time-services-on-one-small-vps</guid>
      <pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate>
      <description>Real numbers from moving a WebSocket game service and a Kafka relay onto a 2 vCPU VPS: the latency, the near-miss, and how much of the plan exists.</description>
    </item>
    <item>
      <title>How Hearso is built: the docs overview</title>
      <link>https://dannielhansel.app/blogs/how-hearso-is-built</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/how-hearso-is-built</guid>
      <pubDate>Thu, 24 Sep 2026 12:00:00 GMT</pubDate>
      <description>What Hearso is, why it exists, and how it is put together. Written for people who want the real shape of it rather than a feature list.</description>
    </item>
    <item>
      <title>Freeing port 8080 shut down Docker, and 28 containers with it</title>
      <link>https://dannielhansel.app/blogs/cron-job-that-stopped-docker</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/cron-job-that-stopped-docker</guid>
      <pubDate>Sun, 20 Sep 2026 12:00:00 GMT</pubDate>
      <description>A July one-liner that killed whatever held port 8080 found Docker Desktop in September. Every link, measured, and the one-line fix with its controls.</description>
    </item>
    <item>
      <title>Eleven route files compared Origin with an address nobody sent</title>
      <link>https://dannielhansel.app/blogs/nexturl-origin-vs-the-host-header</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/nexturl-origin-vs-the-host-header</guid>
      <pubDate>Sun, 20 Sep 2026 12:00:00 GMT</pubDate>
      <description>A 403 where a 401 belonged: what eleven route files were really comparing, the three functions that replaced it, and what two reviewers took back out.</description>
    </item>
    <item>
      <title>67 live checks passed a page with two navigation bars</title>
      <link>https://dannielhansel.app/blogs/the-page-inside-two-frames</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/the-page-inside-two-frames</guid>
      <pubDate>Sun, 20 Sep 2026 12:00:00 GMT</pubDate>
      <description>Local review before pushing left one finding on 70 files. It was real, and none of my 67 live checks could have found it. Here is why, and the guard that can.</description>
    </item>
    <item>
      <title>Eleven checks gave a verdict without looking. Four were mine</title>
      <link>https://dannielhansel.app/blogs/checks-whose-null-case-reads-as-success</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/checks-whose-null-case-reads-as-success</guid>
      <pubDate>Fri, 18 Sep 2026 12:00:00 GMT</pubDate>
      <description>Eleven real checks in one night that reported without examining anything, ten of them as success. What each printed, what it had actually examined, and the rules that replaced them.</description>
    </item>
    <item>
      <title>Hearso answers still ride a 1.5-second poll. Here's the socket path</title>
      <link>https://dannielhansel.app/blogs/how-an-answer-reaches-every-screen</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/how-an-answer-reaches-every-screen</guid>
      <pubDate>Fri, 18 Sep 2026 12:00:00 GMT</pubDate>
      <description>The 1.5-second poll production runs, the WebSocket path we built behind a per-room switch, and how a finished game's points reach DynamoDB.</description>
    </item>
    <item>
      <title>We broke our scripts 51 times. The real bugs were where we didn't look</title>
      <link>https://dannielhansel.app/blogs/mutation-testing-our-own-tooling</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/mutation-testing-our-own-tooling</guid>
      <pubDate>Fri, 18 Sep 2026 12:00:00 GMT</pubDate>
      <description>51 hand-picked mutants against our own tooling scripts. Four survived, and each named a test we hadn't written. The real bugs were in the wiring.</description>
    </item>
    <item>
      <title>My soak runner said FAIL at minute 30. The service was fine</title>
      <link>https://dannielhansel.app/blogs/soak-test-stopped-at-minute-38</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/soak-test-stopped-at-minute-38</guid>
      <pubDate>Fri, 18 Sep 2026 12:00:00 GMT</pubDate>
      <description>Nine conditions read FAIL on a healthy run because the numbers were not in yet. Here is what the restart measured over two hours.</description>
    </item>
    <item>
      <title>Two coding agents shared one file for a night. It taught us 7 rules</title>
      <link>https://dannielhansel.app/blogs/two-agents-one-append-only-file</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/two-agents-one-append-only-file</guid>
      <pubDate>Fri, 18 Sep 2026 12:00:00 GMT</pubDate>
      <description>Locks, timestamps, and orders that were not orders: what one overnight build across two repositories taught me.</description>
    </item>
    <item>
      <title>Uptime Kuma dropped our login, and I was wrong about why three times</title>
      <link>https://dannielhansel.app/blogs/uptime-kuma-login-race</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/uptime-kuma-login-race</guid>
      <pubDate>Fri, 18 Sep 2026 12:00:00 GMT</pubDate>
      <description>Five red checks, three wrong diagnoses, and a socket.io login handler registered after an await. Here's what we measured, and how the race came back.</description>
    </item>
    <item>
      <title>Line coverage said we were done. Mutation testing disagreed</title>
      <link>https://dannielhansel.app/blogs/line-coverage-said-done</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/line-coverage-said-done</guid>
      <pubDate>Wed, 19 Aug 2026 12:00:00 GMT</pubDate>
      <description>99% statement coverage, 76% mutation score on the handler that takes every score. What survived, and what it told us about our tests.</description>
    </item>
    <item>
      <title>Our benchmark passed at 239 ms p95, and we threw it away</title>
      <link>https://dannielhansel.app/blogs/benchmark-trustworthy-as-its-namespace</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/benchmark-trustworthy-as-its-namespace</guid>
      <pubDate>Tue, 18 Aug 2026 12:00:00 GMT</pubDate>
      <description>The run passed and could not be replayed. The reproducibility flaw, the run-scoped namespace that fixed it, and the record that still cites the old run.</description>
    </item>
    <item>
      <title>128 counters cap what a deep rank costs to read, not to write</title>
      <link>https://dannielhansel.app/blogs/histogram-bounds-reads-not-writes</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/histogram-bounds-reads-not-writes</guid>
      <pubDate>Tue, 18 Aug 2026 12:00:00 GMT</pubDate>
      <description>128 log-spaced counters cap what a deep rank lookup costs to read. What that buys, what it costs on the write side, and what we have not measured.</description>
    </item>
    <item>
      <title>One score is 11 writes, and our cost estimate lost its working</title>
      <link>https://dannielhansel.app/blogs/anatomy-of-a-score-submission</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/anatomy-of-a-score-submission</guid>
      <pubDate>Tue, 11 Aug 2026 12:00:00 GMT</pubDate>
      <description>The write fan-out behind one leaderboard score, the $0.68 estimate rebuilt step by step, and the one measurement that disagrees with it.</description>
    </item>
    <item>
      <title>We store scores backwards, so the top 25 is one read and no sort</title>
      <link>https://dannielhansel.app/blogs/store-scores-backwards-so-dynamodb-never-sorts</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/store-scores-backwards-so-dynamodb-never-sorts</guid>
      <pubDate>Tue, 11 Aug 2026 12:00:00 GMT</pubDate>
      <description>The keys, indexes and capacity choices behind our leaderboard tables, grounded in AWS's own papers and docs, with what we measured and what we did not.</description>
    </item>
    <item>
      <title>How I Revamped My Blog — 2025 App Router Edition</title>
      <link>https://dannielhansel.app/blogs/how-i-revamped-my-blog-site-2025</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/how-i-revamped-my-blog-site-2025</guid>
      <pubDate>Fri, 28 Nov 2025 12:00:00 GMT</pubDate>
      <description>A concise, practical walkthrough of the architecture, tech choices, and implementation patterns behind my rebuilt blog using the Next.js App Router, MDX, Tailwind, and modern React tooling.</description>
    </item>
    <item>
      <title>My Favorite Tech Podcasts</title>
      <link>https://dannielhansel.app/blogs/my-favorite-tech-podcasts</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/my-favorite-tech-podcasts</guid>
      <pubDate>Sat, 15 Jan 2022 12:00:00 GMT</pubDate>
      <description>I've compiled a list of my favorite tech and non-tech podcasts.</description>
    </item>
    <item>
      <title>Handling External Links for MDX files in Gatsby</title>
      <link>https://dannielhansel.app/blogs/handling-external-links-for-mdx-files-in-gatsby</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/handling-external-links-for-mdx-files-in-gatsby</guid>
      <pubDate>Fri, 10 Dec 2021 12:00:00 GMT</pubDate>
      <description>The easiest way to open links in a new tab when using gatsby-plugin-mdx.</description>
    </item>
    <item>
      <title>Image types: Vector vs. Pixel</title>
      <link>https://dannielhansel.app/blogs/image-types-vector-vs-pixel</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/image-types-vector-vs-pixel</guid>
      <pubDate>Fri, 03 Dec 2021 12:00:00 GMT</pubDate>
      <description>Why you should go for Vector vs. Pixel.</description>
    </item>
    <item>
      <title>Fetching data from Firestore</title>
      <link>https://dannielhansel.app/blogs/fetching-data-from-firestore</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/fetching-data-from-firestore</guid>
      <pubDate>Mon, 08 Nov 2021 12:00:00 GMT</pubDate>
      <description>This quick guide shows you how to create a React custom hook to fetch data from Cloud Firestore.</description>
    </item>
    <item>
      <title>Initial setup for Cloud Firestore database</title>
      <link>https://dannielhansel.app/blogs/initial-setup-for-cloud-firestore-database</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/initial-setup-for-cloud-firestore-database</guid>
      <pubDate>Mon, 01 Nov 2021 12:00:00 GMT</pubDate>
      <description>This quick guide shows you how to set up Cloud Firestore for your React application.</description>
    </item>
    <item>
      <title>Rebuilding my portfolio site with Tailwind CSS</title>
      <link>https://dannielhansel.app/blogs/rebuilding-my-portfolio-site-with-tailwind-css</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/rebuilding-my-portfolio-site-with-tailwind-css</guid>
      <pubDate>Thu, 13 May 2021 12:00:00 GMT</pubDate>
      <description>My experience with Tailwind CSS.</description>
    </item>
    <item>
      <title>Powerful Morning Routines that Will Change Your Life</title>
      <link>https://dannielhansel.app/blogs/powerful-morning-routines-that-will-change-your-life</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/powerful-morning-routines-that-will-change-your-life</guid>
      <pubDate>Wed, 03 Feb 2021 12:00:00 GMT</pubDate>
      <description>Killer morning routines to better your life and reach your full potential.</description>
    </item>
    <item>
      <title>The Debate between Module vs Package vs Library vs Framework</title>
      <link>https://dannielhansel.app/blogs/the-debate-between-library-vs-package-vs-framework-vs-module</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/the-debate-between-library-vs-package-vs-framework-vs-module</guid>
      <pubDate>Sun, 10 Jan 2021 12:00:00 GMT</pubDate>
      <description>One of the most frequent asked question in Software Engineering.</description>
    </item>
    <item>
      <title>7 Basic Rules for Self Improvement</title>
      <link>https://dannielhansel.app/blogs/7-basic-rules-for-self-improvement</link>
      <guid isPermaLink="true">https://dannielhansel.app/blogs/7-basic-rules-for-self-improvement</guid>
      <pubDate>Fri, 27 Nov 2020 12:00:00 GMT</pubDate>
      <description>What I have learned from doing self-development work.</description>
    </item>
  </channel>
</rss>
