<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>boringtech</title><description>Engineering notes on APIs, data infrastructure, automation and the AI systems built on top of them.</description><link>https://boringtech.dev/</link><item><title>Nigeria’s AI Ambition Needs a Data Foundation</title><link>https://boringtech.dev/posts/nigeria-ai-needs-a-data-foundation/</link><guid isPermaLink="true">https://boringtech.dev/posts/nigeria-ai-needs-a-data-foundation/</guid><description>We should invest aggressively in AI. But not every problem is an AI problem, and AI can&apos;t make up for digital infrastructure we haven&apos;t built.</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>ai</category><category>data-infrastructure</category><category>govtech</category><category>nigeria</category></item><item><title>My Security Scanner Was Grading the Firewall, Not the Site</title><link>https://boringtech.dev/posts/grading-the-firewall-not-the-site/</link><guid isPermaLink="true">https://boringtech.dev/posts/grading-the-firewall-not-the-site/</guid><description>Sites behind Vercel&apos;s bot protection got failing grades for headers they had set correctly. The fix: detect when you reached a wall instead of the site, and grade only what you actually saw.</description><pubDate>Tue, 06 Oct 2026 00:00:00 GMT</pubDate><category>security</category><category>debugging</category><category>product</category></item><item><title>Payment Webhook Handlers That Survive Retries, Duplicates and Forgeries</title><link>https://boringtech.dev/posts/webhook-handlers-that-survive/</link><guid isPermaLink="true">https://boringtech.dev/posts/webhook-handlers-that-survive/</guid><description>A webhook handler that works in a demo can lose money in production. Six rules for handling payment notifications, with code, and how to test each one without a tunnel.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><category>webhooks</category><category>payments</category><category>typescript</category><category>testing</category></item><item><title>Make Your AI Tools Say What They Don&apos;t Know</title><link>https://boringtech.dev/posts/tools-that-say-what-they-dont-know/</link><guid isPermaLink="true">https://boringtech.dev/posts/tools-that-say-what-they-dont-know/</guid><description>Lessons from building an MCP server over Nigerian news and data: an empty result is an answer, and a model will believe whatever your tool implies.</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>ai</category><category>mcp</category><category>api-design</category></item><item><title>A Green Checkmark Is Not Evidence</title><link>https://boringtech.dev/posts/a-green-checkmark-is-not-evidence/</link><guid isPermaLink="true">https://boringtech.dev/posts/a-green-checkmark-is-not-evidence/</guid><description>My scrapers reported 100% success for weeks while inserting nothing. Here is how I changed monitoring to check what a pipeline produced, not whether it exited cleanly.</description><pubDate>Wed, 23 Sep 2026 00:00:00 GMT</pubDate><category>monitoring</category><category>data-pipelines</category><category>operations</category></item><item><title>The Query Wasn&apos;t Slow. The Storage Was.</title><link>https://boringtech.dev/posts/the-query-wasnt-slow/</link><guid isPermaLink="true">https://boringtech.dev/posts/the-query-wasnt-slow/</guid><description>Keyword search on 170,000 news articles took up to 36 seconds. EXPLAIN ANALYZE pointed at the wrong thing. The fix was a narrow table, and search now answers in 29 ms.</description><pubDate>Tue, 15 Sep 2026 00:00:00 GMT</pubDate><category>postgres</category><category>performance</category><category>debugging</category></item><item><title>I Rebuilt Real Government Websites to Find Out What My Design System Got Wrong</title><link>https://boringtech.dev/posts/rebuilding-government-websites/</link><guid isPermaLink="true">https://boringtech.dev/posts/rebuilding-government-websites/</guid><description>A design system tested only on its own docs page is a guess. So I rebuilt ministry websites page for page on afrigov, logged every gap, and fixed the system instead of the pages.</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate><category>design-systems</category><category>accessibility</category><category>govtech</category></item><item><title>LLM Output You Can Trust: Confidence Thresholds and Cited Sources</title><link>https://boringtech.dev/posts/llm-output-you-can-trust/</link><guid isPermaLink="true">https://boringtech.dev/posts/llm-output-you-can-trust/</guid><description>When a model&apos;s answer goes out under a real person&apos;s name, a wrong answer costs more than a blank one. How I made a model cite approved facts, and how code, not the model, decides what gets used.</description><pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate><category>ai</category><category>llm</category><category>python</category><category>structured-outputs</category></item><item><title>Accessibility That Fails the Build</title><link>https://boringtech.dev/posts/accessibility-that-fails-the-build/</link><guid isPermaLink="true">https://boringtech.dev/posts/accessibility-that-fails-the-build/</guid><description>National flag colours are often too light to read as text. afrigov checks every colour pair at build time, derives a readable shade when an official colour fails, and fails the build when anything still doesn&apos;t pass.</description><pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate><category>design-systems</category><category>accessibility</category><category>css</category></item><item><title>Scaling a Security Scanner on Cloudflare Workers</title><link>https://boringtech.dev/posts/scaling-websentry-on-workers/</link><guid isPermaLink="true">https://boringtech.dev/posts/scaling-websentry-on-workers/</guid><description>How WebSentry uses a producer and consumer queue, R2 and an atomic claim to run scheduled scans reliably as the number of monitors grows.</description><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><category>cloudflare-workers</category><category>scaling</category><category>architecture</category></item><item><title>Edge Caching in Front of a Python API: Lessons From Production</title><link>https://boringtech.dev/posts/edge-caching-in-front-of-an-api/</link><guid isPermaLink="true">https://boringtech.dev/posts/edge-caching-in-front-of-an-api/</guid><description>A Cloudflare Worker cache in front of a FastAPI backend: TTLs per path, never caching per-user data, serving stale copies during outages, and why every bad TTL I set showed up as a user-facing bug.</description><pubDate>Wed, 18 Feb 2026 00:00:00 GMT</pubDate><category>cloudflare-workers</category><category>caching</category><category>platform</category></item></channel></rss>