<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Blog · Haruo</title><description>Closed accounts, measurements and mistakes that cost money, in software engineering, AI and automation.</description><link>https://haruo.dev/en/blog/</link><language>en</language><atom:link href="https://haruo.dev/en/rss.xml" rel="self" type="application/rss+xml"/><item><title>False-positive reduction benchmark on synthetic data</title><link>https://haruo.dev/en/blog/false-positive-reduction-benchmark-synthetic-data/</link><guid isPermaLink="true">https://haruo.dev/en/blog/false-positive-reduction-benchmark-synthetic-data/</guid><description>1,200 synthetic alerts, a recorded baseline and two threshold changes, with precision, recall and analyst minutes before and after. Synthetic data, stated on line one.</description><pubDate>Tue, 13 Oct 2026 12:00:00 GMT</pubDate></item><item><title>Alert triage: where the vendor agent ends and your tuning begins</title><link>https://haruo.dev/en/blog/alert-triage-vendor-agent-vs-your-tuning/</link><guid isPermaLink="true">https://haruo.dev/en/blog/alert-triage-vendor-agent-vs-your-tuning/</guid><description>A reference architecture for a 2026 triage stack: what the vendor decides, where the analyst comes in, what the decision log records and what an examiner asks for.</description><pubDate>Tue, 06 Oct 2026 12:00:00 GMT</pubDate></item><item><title>Document Fraud Detection Without ML: in defense of the deterministic engine</title><link>https://haruo.dev/en/blog/document-fraud-detection-without-ml/</link><guid isPermaLink="true">https://haruo.dev/en/blog/document-fraud-detection-without-ml/</guid><description>Same bytes in, same report out: no GPU, no model, no external call. Why a rules engine beats ML in this specific domain, and the engineering the promise demands: an injected clock, versioned weights, a score with semantics, and an engine forbidden to hand down verdicts.</description><pubDate>Thu, 24 Sep 2026 12:00:00 GMT</pubDate></item><item><title>A Design System of Three CSS Files, No Build Step</title><link>https://haruo.dev/en/blog/a-three-file-css-design-system-no-build/</link><guid isPermaLink="true">https://haruo.dev/en/blog/a-three-file-css-design-system-no-build/</guid><description>Three incompatible front-ends (Astro, static HTML, HTML assembled in Python) and one brand. The answer wasn&apos;t a framework: tokens.css, primitives.css, and a generated theme.css, adopted by versioned copy with a check in CI. The decisions, with measured reasons.</description><pubDate>Tue, 22 Sep 2026 12:00:00 GMT</pubDate></item><item><title>Stripe: Charging USD and BRL on the Same Product with currency_options</title><link>https://haruo.dev/en/blog/stripe-usd-and-brl-on-the-same-product/</link><guid isPermaLink="true">https://haruo.dev/en/blog/stripe-usd-and-brl-on-the-same-product/</guid><description>How a SaaS charges the same plan in dollars and in reais on Stripe without duplicating prices: a single Price with currency_options (never &apos;Add another price&apos;, which mints a new id and breaks the webhook&apos;s mapping), server-side quoting in the currency the card will actually pay, and the two different idempotency mechanisms a billing webhook needs: a watermark for plan changes, a PRIMARY KEY for credits. Told through Tamperlens&apos;s real production billing, with every claim about Stripe checked against the official documentation on 2026-08-25.</description><pubDate>Mon, 21 Sep 2026 12:00:00 GMT</pubDate></item><item><title>A Static Site on Cloudflare Pages: The Migration That Shut Down Containers</title><link>https://haruo.dev/en/blog/static-site-on-cloudflare-pages/</link><guid isPermaLink="true">https://haruo.dev/en/blog/static-site-on-cloudflare-pages/</guid><description>How to host a static site on Cloudflare Pages, told through a real migration: a Next.js app with Postgres, an admin panel and API routes became a static export with its data in a ~270 KB JSON read by the browser, and the two containers running it were shut down. The criterion for knowing whether a &apos;dynamic&apos; app is actually static (does anyone besides the owner write?), the migration path, the shutdown checklist that never leaves an orphan hostname poisoning Search Console, what you lose in the conversion, and what it costs (public prices and limits checked on 2026-08-25).</description><pubDate>Sat, 19 Sep 2026 12:00:00 GMT</pubDate></item><item><title>30 Days Solo, From First Commit to Stripe Live: the order that mattered</title><link>https://haruo.dev/en/blog/thirty-days-from-first-commit-to-stripe-live/</link><guid isPermaLink="true">https://haruo.dev/en/blog/thirty-days-from-first-commit-to-stripe-live/</guid><description>The first commit was the plan, the deploy happened within the first hour, and real billing was verified on day 3, with a real card and a refund. The 30-day, 271-commit chronology of Tamperlens, told through the sequencing decisions that transfer to any solo product.</description><pubDate>Thu, 17 Sep 2026 12:00:00 GMT</pubDate></item><item><title>A Self-Hosted GitHub Actions Runner with Docker: The Setup That Survives Billing</title><link>https://haruo.dev/en/blog/self-hosted-github-actions-runner-docker/</link><guid isPermaLink="true">https://haruo.dev/en/blog/self-hosted-github-actions-runner-docker/</guid><description>How to set up a self-hosted GitHub Actions runner on a VPS, with every tool running in a Docker container and nothing installed on the host. Told through the real design of one box running three runners, one per repository, after the hosted-minutes quota ran out. The two container patterns (read-only mount + copy, or --user with HOME=/tmp), deploy-with-rollback authorized by a single script in sudoers, why GitHub&apos;s official documentation says to almost never use self-hosted runners on public repositories (checked 2026-08-25), and the quota guard that warns at 80%, before the next blackout.</description><pubDate>Tue, 15 Sep 2026 12:00:00 GMT</pubDate></item><item><title>How to Build an n8n Community Node from Scratch: Scaffold to Creator Portal</title><link>https://haruo.dev/en/blog/build-an-n8n-community-node-from-scratch/</link><guid isPermaLink="true">https://haruo.dev/en/blog/build-an-n8n-community-node-from-scratch/</guid><description>The full path to creating an n8n node: the package.json contract, declarative vs programmatic, the n8n-node CLI, a per-item execute() with pairedItem, a credential that injects the key without the node ever seeing it, binary data instead of file paths, publishing through GitHub Actions with provenance, and the Creator Portal submission. All of it mapped onto a real, public node, with every claim about the process checked against n8n&apos;s official docs on 2026-08-25.</description><pubDate>Mon, 14 Sep 2026 12:00:00 GMT</pubDate></item><item><title>VPS Backup: a 3-2-1 Design on a Single Box</title><link>https://haruo.dev/en/blog/vps-backup-3-2-1-on-a-single-box/</link><guid isPermaLink="true">https://haruo.dev/en/blog/vps-backup-3-2-1-on-a-single-box/</guid><description>How to apply the 3-2-1 backup rule to a single VPS: consistent dumps on the box itself, the provider&apos;s automatic backup as the second copy (on Hetzner: 20% of the plan for 7 daily copies) and why it does not count as the off-site copy, plus the nightly pull that takes the data outside the provider. With the cost of each layer in public prices, checked on 2026-08-25.</description><pubDate>Sat, 12 Sep 2026 12:00:00 GMT</pubDate></item><item><title>A Verified n8n Community Node: the rules the docs don&apos;t emphasize</title><link>https://haruo.dev/en/blog/a-verified-n8n-community-node/</link><guid isPermaLink="true">https://haruo.dev/en/blog/a-verified-n8n-community-node/</guid><description>Zero runtime dependencies, binary data instead of file paths, CI-only publishing with provenance, and the whole afternoon npm&apos;s OIDC cost. What verification of a community node actually requires, with the mistakes in the order they happened.</description><pubDate>Thu, 10 Sep 2026 12:00:00 GMT</pubDate></item><item><title>How Cloudflare Access Works: Admin Protected Without Writing a Login Page</title><link>https://haruo.dev/en/blog/how-cloudflare-access-works/</link><guid isPermaLink="true">https://haruo.dev/en/blog/how-cloudflare-access-works/</guid><description>How Cloudflare Access works in practice: the edge authenticates (SSO or one-time PIN by email), injects a signed JWT into a header, and your admin panel gets a login without you writing one. The design used on two real admin surfaces (a third-party app and an in-house app), the common mistake of trusting the proxy without validating the token, why failing closed matters, and when NOT to use it. Naming and public prices checked against Cloudflare&apos;s documentation on 2026-08-25.</description><pubDate>Tue, 08 Sep 2026 12:00:00 GMT</pubDate></item><item><title>Hostname Sunset Without Poisoning Search Console</title><link>https://haruo.dev/en/blog/hostname-sunset-without-poisoning-search-console/</link><guid isPermaLink="true">https://haruo.dev/en/blog/hostname-sunset-without-poisoning-search-console/</guid><description>An orphaned subdomain serving 502s polluted the index report of the entire domain: with an sc-domain property, one dead hostname&apos;s error becomes everyone&apos;s problem. The runbook that stuck (permissive robots, 410 on the API, 301 on the rest) and the right teardown order.</description><pubDate>Mon, 07 Sep 2026 12:00:00 GMT</pubDate></item><item><title>What WhatsApp Support Automation Actually Costs: the cost components of a self-hosted stack</title><link>https://haruo.dev/en/blog/what-whatsapp-automation-actually-costs/</link><guid isPermaLink="true">https://haruo.dev/en/blog/what-whatsapp-automation-actually-costs/</guid><description>The real bill for automating WhatsApp support on a self-hosted stack: a VPS from ~€6/month, Meta&apos;s fees (free to reply inside the 24-hour window; a per-message rate card for the rest), LLM costs measured in cents per conversation, and maintenance, the component that dominates the bill and decides when a ready-made SaaS is cheaper. Every price is public, with source and date.</description><pubDate>Sat, 05 Sep 2026 12:00:00 GMT</pubDate></item><item><title>Prompt Caching: Measure the Prefix Before Flipping the Flag</title><link>https://haruo.dev/en/blog/prompt-caching-measure-the-prefix-first/</link><guid isPermaLink="true">https://haruo.dev/en/blog/prompt-caching-measure-the-prefix-first/</guid><description>How to decide whether prompt caching is worth enabling: decompose the payload part by part, prove the prefix is stable byte for byte (here it was 99.8%), put the breakpoint at the end of the system prompt so it covers the tool definitions too, and ship the meter with the feature. With a Monday-morning checklist and what still can&apos;t be claimed.</description><pubDate>Thu, 03 Sep 2026 12:00:00 GMT</pubDate></item><item><title>Multi-Tenant Agents: a Capability Firewall in Code, Human Approval in the Channel</title><link>https://haruo.dev/en/blog/multi-tenant-agents-capability-firewall/</link><guid isPermaLink="true">https://haruo.dev/en/blog/multi-tenant-agents-capability-firewall/</guid><description>A multi-tenant agent service in one process: schema per tenant, deny-by-default on the filesystem, tools removed from the registry before the graph exists, and human approval where silence is never a yes. The patterns, with the two inversions that nearly cost dearly.</description><pubDate>Tue, 01 Sep 2026 12:00:00 GMT</pubDate></item><item><title>How an MCP Server Works, explained by someone who published one</title><link>https://haruo.dev/en/blog/how-an-mcp-server-works/</link><guid isPermaLink="true">https://haruo.dev/en/blog/how-an-mcp-server-works/</guid><description>What an MCP server is, the full lifecycle of a call (handshake, tools/list, tools/call), the difference between tools, resources and prompts, stdio versus HTTP, and what changes about security when the server touches disk and network. Explained with a real server, published to npm and the official MCP Registry.</description><pubDate>Mon, 31 Aug 2026 12:00:00 GMT</pubDate></item><item><title>A Backup With a Dead-Man Switch, and the restore rehearsal that must know how to fail</title><link>https://haruo.dev/en/blog/backup-with-a-dead-man-switch/</link><guid isPermaLink="true">https://haruo.dev/en/blog/backup-with-a-dead-man-switch/</guid><description>The design where silence becomes the alarm: the job pings when things go right, so the watcher never depends on the watched to raise it. The evidence that this is needed: a nightly backup sat dead for 14 days with nobody noticing, because failure alerts can&apos;t catch the job that never runs. Plus the quarterly restore rehearsal that verifies even its own ability to fail.</description><pubDate>Sat, 29 Aug 2026 12:00:00 GMT</pubDate></item><item><title>One VPS, Zero Open Service Ports: Anatomy of a Tunnel That Serves Everything</title><link>https://haruo.dev/en/blog/one-vps-zero-open-ports-cloudflare-tunnel/</link><guid isPermaLink="true">https://haruo.dev/en/blog/one-vps-zero-open-ports-cloudflare-tunnel/</guid><description>Every service on a single box, no exposed HTTP port: traffic comes in through a Cloudflare Tunnel, admin sits behind Access, and what&apos;s internal has no hostname at all. The design, the trust boundaries, and the compose traps that cost real incidents.</description><pubDate>Fri, 28 Aug 2026 12:00:00 GMT</pubDate></item><item><title>An MCP Server for Your API: the packaging decisions that matter</title><link>https://haruo.dev/en/blog/mcp-server-for-your-api-packaging-decisions/</link><guid isPermaLink="true">https://haruo.dev/en/blog/mcp-server-for-your-api-packaging-decisions/</guid><description>File paths instead of base64, confined directories with symlinks resolved, package version locked to the engine version by test, registry namespace via DNS. The decisions behind packaging an API as an MCP server, and the honest read on registries as a distribution channel.</description><pubDate>Wed, 26 Aug 2026 12:00:00 GMT</pubDate></item><item><title>Publishing Your False Positive Rate: The Differentiator Almost Nobody Has</title><link>https://haruo.dev/en/blog/false-positive-rate-honest-measurement/</link><guid isPermaLink="true">https://haruo.dev/en/blog/false-positive-rate-honest-measurement/</guid><description>In document fraud detection, measuring recall is the easy part. Measuring and publishing your false positive rate across separate populations of legitimate documents is the discipline that separates an honest product from security theatre. With real numbers from Tamperlens and the federal standard almost nobody meets.</description><pubDate>Mon, 24 Aug 2026 12:00:00 GMT</pubDate></item><item><title>How a Tampered PDF Reveals Itself: Forensics of Structure, Not Appearance</title><link>https://haruo.dev/en/blog/how-a-tampered-pdf-reveals-itself/</link><guid isPermaLink="true">https://haruo.dev/en/blog/how-a-tampered-pdf-reveals-itself/</guid><description>An edited PDF almost never looks edited, but the edit is written into the file&apos;s structure: incremental revisions, the /Prev chain, replaced objects, the signature&apos;s /ByteRange. How to reason about a PDF from its structure, with the real mechanism Tamperlens uses.</description><pubDate>Mon, 24 Aug 2026 12:00:00 GMT</pubDate></item><item><title>Reliable Agentic AI: The Patterns I Run in Production (Not the Hype)</title><link>https://haruo.dev/en/blog/reliable-ai-agents/</link><guid isPermaLink="true">https://haruo.dev/en/blog/reliable-ai-agents/</guid><description>Subagents that verify adversarially, published numbers that derive from a test, a human approval loop with a safe fallback, the agent that can&apos;t approve itself by silence. The real engineering patterns behind reliable agents, with the reason for each choice.</description><pubDate>Mon, 24 Aug 2026 12:00:00 GMT</pubDate></item><item><title>Quality Gates That Pass Without Running: four failure modes to hunt in your CI</title><link>https://haruo.dev/en/blog/the-ci-that-lied/</link><guid isPermaLink="true">https://haruo.dev/en/blog/the-ci-that-lied/</guid><description>A link check that looks at 21 of 74 pages, a binary that dies in the linker, a pipe that swallows the exit code, a lint that was never installed. Four ways a gate stamps ✅ without doing the work, and the five-minute test that exposes each one.</description><pubDate>Sun, 23 Aug 2026 12:00:00 GMT</pubDate></item><item><title>The Test That Derives the Published Number</title><link>https://haruo.dev/en/blog/the-test-that-derives-the-published-number/</link><guid isPermaLink="true">https://haruo.dev/en/blog/the-test-that-derives-the-published-number/</guid><description>The pattern: every number printed on a public surface derives from the source of truth through a test that breaks in CI, not through periodic review. How to write that test, where it earns its keep, and what it costs when it isn&apos;t there.</description><pubDate>Sun, 23 Aug 2026 12:00:00 GMT</pubDate></item><item><title>When GitHub Actions Dies on Billing: a runbook for the silent failure mode</title><link>https://haruo.dev/en/blog/when-github-actions-dies-on-billing/</link><guid isPermaLink="true">https://haruo.dev/en/blog/when-github-actions-dies-on-billing/</guid><description>The runbook for when your hosted-minutes quota runs out: how the 2-second red job presents itself, how to tell what stopped loudly from what stopped silently, what to restore first, and why the watcher cannot live on the box it watches.</description><pubDate>Sun, 23 Aug 2026 12:00:00 GMT</pubDate></item><item><title>Persistent Memory for AI Agents with Honcho</title><link>https://haruo.dev/en/blog/persistent-memory-ai-agents-honcho/</link><guid isPermaLink="true">https://haruo.dev/en/blog/persistent-memory-ai-agents-honcho/</guid><description>Learn how to implement persistent memory in your AI agents using Honcho, an open-source platform for managing episodic, semantic, and procedural memory.</description><pubDate>Tue, 26 May 2026 12:00:00 GMT</pubDate></item></channel></rss>