Engineering Notes

Patterns from building AI agent systems for daily use — what worked, what failed, and why.

AI Agent Architecture

Your Tests Were Green Because the Gate Was Never Wired In

A publish-blocking gate was implemented, unit-tested and green — and absent from the dispatch tuple the pipeline actually iterates, so it had never once run. Deleting it from the tuple leaves its own test file at 18 passed while a wiring test fails by name. Green proves behavior; reachability needs its own evidence.

testingpythonarchitecturedebugging

When You Delete a Rule, Hunt the Tests That Went Quiet

I deleted a validation rule that had never once been right, and twenty tests turned red — that part was bookkeeping. The four tests that stayed green were the ones that had quietly stopped testing anything at all.

testingtddpythonai

The patch and the test were wrong in the same direction

A model fixed “main() can never exit non-zero” by appending sys.exit(0), and my test passed it — because the assertion checked that a sys.exit call existed, not that it could be non-zero. Both had compressed the same English requirement the same shallow way. An AST sweep comparing every docstring’s stated intent against its assertions found a second divergence, a half-assertion that forbade the wrong answer and never required the right one.

testingaicodequalitydebugging

RDU: Reusable Decision Units for Consistent AI Agents

How to make AI agents give consistent decisions across sessions using versioned, trigger-driven rule files. 140+ rules across iOS, trading, AI agent design, game development.

AI agentsconsistencyClaude Code

Falsifier-Driven AI Decisions: No Claim Without Falsification Conditions

How to prevent LLM agents from hallucinating probabilities and accepting unverifiable multi-agent consensus. Includes real metrics: council_repeat_rate 0.44, empty_consensus_rate 0.354.

AI agentshallucinationmulti-agent

How to Make an AI Research Agent Label Facts vs Inferences

Stop a RAG agent from presenting inferences as facts: let the LLM only extract, and let deterministic code score and label FACT/INFERENCE with a ≥2-independent-source rule and required evidence IDs.

provenanceRAGhallucination

Claude Code Stop Hooks as Behavioral Gates

Using Claude Code hooks to enforce behavioral constraints beyond prompts. AND-gate design, nag-once pattern, decision-ownership and sycophancy-prevention examples.

Claude Codehooksbehavioral gates

My probe passed because it could not fail

A pre-registered waveform check said my audio crossfade survived an FCPXML roundtrip. It hadn't — the test content I prepared made failure invisible to the metric, so the check could not fail either way. The real verdict came from the exported XML and frame geometry, and both overturning clues were already sitting in the same results file the pass came from.

testingdebuggingvideoverification

I Confirmed My API Formula at the One Point Where Both Formulas Agree

A live measurement against a video editor's scripting API convinced me an audio clip's end-frame semantics were inclusive, and I wired that formula into a production pipeline. The next session's test rig changed one variable my original measurement never varied, and the formula turned out to be a special case of a more general one.

apidebuggingtestingprogramming

My Caption Width Guard Passed Every Test. It Was Measuring Text the Renderer Never Drew.

A subtitle line-wrap width guard measured text in uppercase to get a conservative pixel budget, but the renderer draws mixed case. The guard fired early, produced worse one-word chunks than the bug it was fixing, and every test stayed green — only looking at a rendered frame caught it.

testingpythondebuggingvideo

The Upload Succeeded, the Record Did Not

A YouTube upload stage wrote its local "already uploaded" record only after verification succeeded, so a verification failure left the video live on the platform with nothing on disk to say so. Re-running the same command sailed past the duplicate guard and would have uploaded a second copy of a video that already existed.

reliabilityapiidempotencydevops

The Checkpoint Remembered the Result, Not the Request

A checkpoint-before-verify fix correctly recorded a video ID the moment it came back, but the resume path re-derived what counted as correct from today's CLI flags and config instead of the request the checkpoint had actually recorded — and a clean resume set off a false "downgrade detected" alarm.

aidevopsdebuggingtesting

Your glossary gate passes words, not names

In a glossary gate, a coined name passed because every word in it was real — dictionary-listed, attested on the page — while the name itself read like a translation. Two of three reader challenges were right, and the discriminator that could have caught it was already sitting in two other names I hadn't checked against.

namingwritingAI agentscode quality

A Substring Is Not a Speech Act: My AI Agent Executed Questions and Quotes

A small language-binding bug let questions, negations, and quoted text trigger an AI agent's actions. The repair replaced substring matching with a finite authored grammar and a whole-response fail-closed check.

aijavascripttestingdebugging

My AI Agent Pipeline Cut Wall Time and Used More Tokens

One multi-agent episode reached review sooner while total input and recovery work rose. Time to a candidate and total work consumed are separate measurements, so the handoff boundary needs an explicit budget.

aimeasurementdevopsproductivity

First Payoff Is Not the Final Answer: A Python Timing Gate

A short-video timing gate reused an early visual payoff as the final answer reveal. Separating those events made the check a testable contract instead of a plausible duration rule.

testingpythonvideoai

Entitlement Is Not Balance: Don't Authorize Google Flow Spend with Arithmetic

An included-credit entitlement, a current balance, and a debit priority are different facts. Authorization needs fresh, source-specific evidence for the pool it will consume.

billingsecuritytestingapi

The Ablation Had Four Arms. None Matched What Shipped.

Four arms existed before I wrote the fix, and none of them reproduced what I deployed: one flag toggled two independently shippable changes together, so no number could be attributed to either. The conclusion reversed three times, and each reversal came from splitting that axis one notch further — not from new evidence.

ablationexperiment designAI agents

The Count Read in the Thousands. It Was Thirty-Seven Things, Recounted.

An audit reported 3,206 hits and I was about to cite it as scale. Behind them were 37 distinct entries, one re-selected 1,274 times — the mirror image of a checker returning a false zero. The test is one division: unique items over total hits, plus the question of whether the counter or the system is doing the repeating.

observabilitymeasurementAI agents

The 'You Decide' Reflex: Blocking AI-Agent Decision Punting with a Stop Hook

An agent that has gathered all the data to decide will still hand the choice back — "which do you prefer?" — because the training gradient rewards deference. A deterministic Stop-hook with an AND-gate (deflection phrase AND fresh tool evidence) blocks it while letting genuine value questions pass.

Claude Codehooksdecision ownership

The Gate Only Logged When It Fired. I Replayed 116,022 Candidate Stop Points to Find the Rest.

A Stop hook recorded only distinct blocks, leaving no denominator. Replaying its deterministic five-outcome logic over 5,537 retained transcripts recovered 116,022 candidate Stop points and a counterfactual trigger rate — without waiting for new instrumentation.

AI agentsobservabilityhooks

Eight Frames Said Fail. Twenty-Four Said Pass.

A pre-registered threshold fixed a pass line (motion median at least 50% of the original) but never fixed the frame count behind it, so the same clip scored 47.5% and 56.5% depending on how it was measured. The rule I wrote to fix that then exposed a second problem one layer down — a compliance rate is only as good as the denominator nobody had defined for it.

statisticstestingdatascienceai

Two of Five Gates Replayed Clean. The Other Three Read a Ledger With No History.

Replaying a deterministic gate's logic over retained transcripts recovers a trigger rate no counter ever wrote — but only for gates whose entire predicate lives in the log. Three of five read live external state with no change history, so their denominator is not unmeasured but undefined relative to the archive. Also: five fingerprint files in one format holding three different quantities, and dedup compression that differs 3.5x between instruments.

AI agentsobservabilityinstrumentation

Do Multiple Personas on One LLM Give Real Diversity, or Do You Need Different Model Families?

Multiple personas on a single LLM do not give you real diversity — they are prompt variations of one set of weights, so they share the same blind spots, and the only durable d

aillmarchitecture

How to Stop AI Agent Skills, Hooks, and Cron Jobs from Silently Conflicting Over Where They Run and What Data They Trust

Make every skill, hook, and scheduled job declare four invariants before it ships — Locality (where it can run), Source-of-truth (which facts it owns or borrows), Cross-ref (w

aiagentsdevops

If an LLM Extracts the Inputs, Is Your Deterministic Score Really Deterministic? Stopping Provenance Laundering

No — a scoring function that consumes whatever values an LLM hands it is only deterministic in name; the LLM's judgment launders straight through the "deterministic" gate, and

llmsecurityarchitecture

The Gate Couldn't Read My JavaScript, So I Removed the Numbers From It

A publishing gate that blocks any unsourced number on a page cannot read inside a script tag, which breaks the moment a page needs a JavaScript calculator. Instead of teaching the gate to parse JavaScript, or exempting scripts from the check, I restructured the calculator so its JavaScript never contains a domain number at all.

testingarchitecturejavascriptcodequality

Claude Code "400: no low surrogate in string" on every turn: repairing a permanently broken session transcript

A Claude Code session that returns API Error: 400 ... not valid JSON: no low surrogate in string on every turn is poisoned by a lone UTF-16 surrogate (a code point in U+D800–U

claudecodedebuggingpython

Model or Method? Building a Deterministic Lab to Measure an AI Agent Fleet's Own Behavior

A one-time audit said an agent's quality is the method, not the model — so we built a stdlib SQLite lab to measure method vs outcome across 155 real sessions, reassembling logical sessions and fingerprinting which disciplines each model-epoch used.

aillmagents

A Fair Coin Isn't Enough: When a Perfectly Randomized Experiment Is Impossible to Analyze

A cryptographically fair A/B assignment was still unanalyzable — nothing joined the random draw to the task it dispatched, so no code could compute the intention-to-treat comparison. The join, the re-draw guard, and the up-front power calc are the experiment; the coin is the easy part.

datasciencestatisticsexperiment design

Perfect Instrumentation Won't Save an Underpowered Experiment

A pre-registered randomized study logged 177 draws, froze its primary metric and honored its falsifier — yet still had to terminate undeterminable. Its attainable sample could detect an effect 6.7 times larger than the observed primary gap, and a repaired join would have needed about 45 times more observations per arm.

datasciencestatisticsexperiment design

The Silent 10× Tax: How a Nondeterministic System Prompt Voids Your LLM Prompt Cache

Prompt caching is a prefix match, so one timestamp or unsorted JSON key in the system prompt makes every later token miss the cache — a silent 10× cost leak no error reports. How it fails, the invalidator list, and how to assert cache_read_input_tokens > 0.

llmprompt cachingcost

Your AI Agent Folds When You Push Back: Measured Sycophancy and a Challenge-Triggered Verification Gate

LLMs measurably reverse correct answers under "are you sure?" (98% in one Anthropic measurement), and self-critique can't fix it — the critic shares the producer's blind spots. The fix is architectural: a Stop-hook gate that forces one cross-family re-verification on challenge, then allows only HOLD-with-evidence or CHANGE-with-reason.

llmsycophancyverification

My Verification Gate Cleared on a Keyword, Not Evidence

A reader turned the sycophancy gate above into an observable test, and it failed: the escape condition was a verification keyword in the agent's own prose, so writing "I re-verified this cross-family" cleared it with nothing behind it. Replaying the tightened rule over 212 transcripts newly blocked 0 legitimate turns — and the fix still only proves that a tool ran, not that it ran on the claim.

verificationstop-hookself-report

Five Fact-Check Gates and a Signature Passed a Page Whose Source URL Never Renders the Number

A page that had already passed five machine gates and a human's signature turned out to cite a source URL that never renders the number it was cited for, because every check compared the fact-check sheet against itself instead of against the source's actual rendered text.

testingverificationarchitectureai

Five Automated Gates Passed Three PayPal and Stripe-vs-Square Fee Pages. One Human Reader Rejected All Three.

Three AI-written pages passed five separate automated fact-checking gates and a 7-item self-check on the first try. One human read-through rejected all three anyway — for a wrong-vendor attribution, a claim a sibling page disproved, and a downstream cross-page check that never ran for pages built one at a time.

aitestingseoautomation

The Rule That Triggered on Its Own Advice

I wrote a rule to stop my AI agent from delegating tasks it could do itself. The rule matched on words, and its own prescribed fix contained the exact words it was matching on — so following the rule correctly re-triggered the rule.

aillmdebuggingarchitecture

Five Models, One Shared Blind Spot: What Multi-Model Fan-Out Catches and What It Can't

Fanning one evidence digest out to five model families: 68/68 numeric claims survived recomputation, four models caught an anomaly the fifth missed — and all four external models missed an experiment-design flaw sitting in plain sight. Convergence on the same framing is cross-consistency, not independent evidence.

multi-modelverificationllm

Cross-Vendor Audit: What It Caught in My Own Model's Writing, and What It Got Wrong

A different-vendor LLM audited ten queued posts written by my main model: it caught three copy-paste-breaking macOS/Linux platform bugs and a destructive in-place file conversion the writing family repeatedly missed — and also filed a false accusation that only grepping the primary source could refute. Cross-family audit works; auditor self-reports still need re-verification.

cross-vendorllmverification

I Asked Three Judges If I Was Wrong. One JSON Field Decided the Answer.

A reader's rebuttal sent me to three judges before I replied — my own code review plus two model vendors. The table that came back looked like proof cross-vendor verification pays off; it was actually a schema bug. Only one model's prompt had a field for disagreement, and a same-model controlled experiment (n=3 per condition) showed the schema decided the verdict, not the vendor.

llm-as-judgeverificationprompt schema

A Forced Dissent Slot Has a Floor: Read It by Convergence, Not Presence

The field that fixed the schema bug above turned out to have a second failure mode. A mandatory "where does this overreach" slot gets filled even when there is nothing to object to, because the model cannot write nothing — so a populated field is not the signal. What is: whether two independent model families, shown the same material, land on the same objection.

llm-as-judgeprompt schemaverification

An Empty Prompt Is Not a Blind Review

I thought an adversarial reviewer was blind because I left my conclusion out of its prompt, until its own search tools found the conclusion I'd already written to disk. Blind is a property of what a reviewer can reach, not of what you tell it.

aitestingarchitecturedebugging

One Leg Can Raise an Objection. It Can't Settle One.

Collecting a dissenting opinion and using it to overturn a conclusion are not the same operation, and they don't need the same quorum — conflating them made two of my own verification rules contradict each other.

aitestingarchitecture

Route the Claim to Its Verifier - Legs Are Not Votes

I stopped running every verification tool on every load-bearing claim in my agent fleet and started routing each claim type to the one verifier that can actually check it — because counting legs isn't the same as counting independent axes.

aillmarchitecture

When Two AI Reviewers Disagree, Read What They Both Rejected

A two-model review panel split on half its rulings, and I had been treating each split as a tie. Counting what both models rejected — instead of what each one picked — resolved every split, because a choice carries the model's disposition and a cited rejection doesn't.

aillmarchitecture

The Bug Was in the Brief, Upstream of Both Reviews

A delegated writing brief fed the same four wrong factual claims to both an AI writer and an independent reviewer, and the review passed anyway — because a reviewer that only checks a draft against its source can't refute a claim the source stays silent on.

aillmtestingarchitecture

Your Agent Telemetry Ranks Your Routing Policy, Not Your Models

Five models, two roles, a few thousand real agent threads — and a stack of refusals instead of a ranking: role confounds, version-epoch discipline, [0,0] tie-degenerate bootstrap CIs, non-additive token counters, self-measurement contamination. The one completion-proxy CI worth reading spans zero.

llmtelemetrydatascience

Your LLM Telemetry Table Does Not Have One Denominator

A routed LLM telemetry table can put several incompatible populations under one model label. The comparison becomes honest only after model epoch, role, analysis unit, and proxy eligibility are kept separate.

aitestinganalyticsllm

Four Models Cited My Numbers Perfectly. One Still Misread Them.

Four model families cited every number from a frozen agent-telemetry table with zero errors — 70 of 70 recomputed within tolerance — and one still read a row of structural zeros as error-free tool use and built a routing suggestion on it. The one pre-registered equivalence test that passed cleared a margin 0.75 standard deviations wide while its own interval excluded zero. A citation audit is a copy-fidelity floor; it never checks the inference drawn from the number.

multi-modelverificationstatistics

Deterministic Tool Adoption Gates: Score It, Don't Vibe It

A new skills repo scored 64/100 → TRIAL across five gates (maturity, dependencies, platform fit, policy, trajectory) on provenance-tagged inputs (9 FACT / 1 ASSUMPTION, conservative defaults for assumptions), with five auto-derived kill conditions — and a refusal to log a day-zero outcome that would pollute the ledger's own base rates.

adoptionfalsifierdecision

Rotating the Hostile Seat: A Six-Round Adversarial Design Review Before Hardening an Agent

Three roles — question, defend, attack — rotated through three reviewer groups in all six permutations, so no group was ever the permanent judge. Seven confirmed defects before hardening, including a fix two groups had agreed on that a later hostile seat reversed as unsafe, and a verification pool that fell back three layers deep in round one.

adversarial reviewmulti-agentverification

Our Quality Gate Was 24x Noisier Than What It Guarded

A pre-registered gate used a holdout roughly 24 times noisier than the leaderboard it was protecting, so its threshold was cleared zero times in 125 days. A near-empty pass log is a symptom, not proof the gate works — and the fix is to move the gate to a different axis, not to enlarge the noisy instrument.

measurementpre-registrationexperiment design

Two Gates, No Legal Move

My publish-pass agent hit a beat that no source label could satisfy — every relabel that cleared one automated gate tripped another, provably, by arithmetic. The fix wasn't to relabel harder; it was a recorded, attributable waiver, reserved only for what was actually unfixable.

aitestingautomationdevops

Sub-Agent Metrics Are Not Comparable to Main-Thread Metrics

Across a few thousand agent threads, the main-thread vs sub-agent split moved metrics by up to 135x, and the role mix ranged from 1.5% to 71.4% per model — so pooled per-model averages were weighted averages with different weights. One pair showed a 3.6x pooled gap that exists in neither stratum. Plus two traps that survive stratification: metrics that change meaning per stratum, and bootstrap intervals that collapse to [0, 0] on tied data.

agent telemetrystratificationstatistics

The Confidence Interval Was [0, 0]. That Was Not Precision.

A weekly stratified comparison report now carries a named footnote admitting that its own bootstrap confidence intervals can collapse to [0, 0] under heavy ties, and still prints thirty of them, unflagged, in the same snapshot. A documented limitation is not a fixed one.

aistatisticsdatasciencetesting

The Observed Maximum Is Not the Structural Maximum: Set a Compliance Gate's Budget from Code, Not from Three Samples

A gate's budget for unmeasurable checks was set from the highest count seen in three sampled episodes, but the sample had only ever visited one branch of a two-branch pipeline, so the observed maximum was a lower bound on the real structural maximum. The fix was counting the mechanism in code instead of waiting for more data.

aitestingsoftwareengineeringstatistics

Same Bytes, 20% Fewer Tokens: Token Counts Are Model-Scoped

Two sub-agent spawns with near-identical request bodies (Δ0.3%) were billed 246,525 vs 196,892 input tokens — the smaller model metered 20.1% fewer tokens for the same bytes. A token count is a property of the (request, model) pair, so cross-model dollars-per-token comparisons need a byte- or task-normalized denominator.

llmtokenizationcost

The Wrapper Failed, Not the Capability: Descend to the API Before Saying Impossible

A tool failing and a tool being incapable are different claims, and the error in front of you does not say which. Descend one layer, call the underlying service directly with the same credentials, and let that decide — skipping the descent is how a client-side parsing bug gets laundered into a permanent capability judgment.

AI agentsdiagnosistool wrappers

Fleet Monitoring & Orchestration

Aggregating cron and macOS launchd into one read-only dashboard — without migrating either

See every cron job and LaunchAgent in one place by globbing on-disk state instead of importing them. Includes a 25-tool fit-gap matrix and the read-only aggregation pattern.

cronlaunchdobservability

Why I Rejected an Event Bus for My Solo Agent Fleet: State Is Truth, Events Are Rumors

Why pull (scan on-disk state) beats push (an event bus) for monitoring a high-churn fleet with components you don't control. The instrumentation-tax argument and self-healing polling.

multi-agentpull vs pushMCP

Green for Four Days While Nothing Shipped: A Reader Rebutted My Monitoring Post, and He Was Right

A commenter showed that polling files the job itself wrote is self-report over a filesystem — the same weakness as the event bus I rejected. My publishing job proved its own health with its own log and stayed green through a four-day outage. The cross-vendor verification I ran instead of defending, and the effect_probe fix.

observabilityliveness without progresspostmortem

Fixing the Proxy Deleted the Objective: The Style Review Removed a CTA and Every Accuracy Gate Passed

A style review's fix for an "unrelated CTA" finding was a full removal that passed every accuracy gate while silently deleting the conversion funnel the CTA carried, and the resulting silence got reported as "not enough data yet" instead of "no path for data to arrive."

testingarchitecturecodequalityproductivity

A Measurement That Never Ran Became a Verdict: A Second Automated Chrome Answered for the First

A biweekly monitoring script kept completing and printing a confident verdict even though every browser read had failed, because a second automated Chrome instance silently answered in place of the first.

monitoringautomationpythondevops

The Overlap Check Said Zero Overlaps on the Same Clip Three Times. Each Time It Answered the Wrong Question.

An overlap check on a video pipeline passed three times on clips where text was visibly unreadable. It never lied — each time it was correctly answering a narrower question: a caption layer it never draws, a same-color collision its own pair definition can’t represent (so the worst case, perfectly co-located, is the least visible), and a pixel signal that on measurement carried no usable information at all. The third one I shipped as a ranking, not a verdict. Also: the repair helper reproduced the exact overlap it existed to remove.

testingdebuggingsoftwareengineeringautomation

Same Video File, Same Threshold, Three Answers: Caption Safe-Zone Frames Are Matched by Grid, Not by Count

A caption safe-zone check failed a clean video clip, and re-running the identical check three different ways produced three different answers on the same file, because the two renders being compared were sampled on independently-computed timestamps instead of a shared frame index.

testingpythondebuggingautomation

It fit in memory and was still unusable — do the bandwidth arithmetic first

A 15GB model loaded fully onto the GPU with no swap, and generated at 5.6 tokens per second. The arithmetic ceiling — bandwidth divided by bytes touched per token — was 8. At a ratio of 0.70 you’re bandwidth-bound, which means the obvious fix (quantize smaller) buys under 9% while costing real quality. Capacity is free to check, which is exactly why it gets mistaken for a verdict on throughput.

performancemachinelearninghardwarearchitecture

Four MCP Tools Died the Same Day. One Unpinned SDK Dependency Killed Three.

Different repos, different authors, different purposes, all dead on the same morning with the same useless Connection closed. Independent failures don’t synchronize — a shared unpinned dependency does. Also: why pinning everything trades three outages for twenty-two units of staleness debt, and the delegation rule that has to ban operators rather than intentions.

devopspythonarchitecturedebugging

The dedicated OCR engine lost to the general-purpose model — 300× slower

The specialist read the image 300 times faster and made four times as many character errors, which wasn’t what decided it. It returned the table decomposed by column, so which value belonged to which row was unrecoverable — and that output is syntactically perfect, so no cheap-first fallback can detect it. Escalation ladders are only sound when the cheap tier’s failure is visible at the boundary.

machinelearningaiarchitecturetesting

For weeks I logged a CLI as flaky. The bug was | tail -20.

Three sessions of lsof later: the CLI returned in seconds every time. An unrelated npm process spawned in the same second had inherited the write end of my pipe, so head and tail blocked forever waiting for an EOF that could never arrive — and the timeout wrapper couldn’t help, because it only reaches the process that already exited. In one case a 36-byte error message spent 81 minutes stuck in the pipe.

unixbashdebuggingdevops

One API Key Turned the Gateway's Cooldown Into a 60-Second Blackout, and I Blamed the Vendor for Months

A single API key meant a routine upstream 5xx put the whole provider into a 60-second local blackout inside my own gateway, and for months I read the retries that always failed inside that window as proof the vendor itself was unreliable.

devopsdebuggingapiai

There was no valid config. The API had no word for the subject.

A generated scene framed 93% of the wrong country, and two sessions went into fixing the script. No script could have worked: the parameter took country codes and the subject wasn’t a country. An expressiveness gap and a misconfiguration look identical from the output — wrong result, plausible config, no error — but one is fixed by changing a value and the other by widening the grammar.

apidebuggingarchitecturepython

Your dead-code detector found six orphan constants. None of them were dead.

Six constants were defined in one file and referenced nowhere outside it — the standard shape of dead code. Every one turned out to be a specification sitting beside code that had retyped the same values as string literals, with nothing joining the two. Two of them were letting a one-character typo skip a review gate entirely. Zero references is a measurement of the joint, not a verdict on the constant.

pythontestingcodequalityarchitecture

Exclusion Lists Managed by Name Always Rot. Mark the Population Instead.

A denylist of page slugs broke the same day I wrote it, and the fix was to stop naming what to exclude and start reading a structural marker the pages already carry.

testingcodequalityarchitecturesoftwareengineering

I wrote a rollback rule and no way to read the number

The reversal condition passed review — a threshold, a remedy, a falsifier. Then I went to check it and found none of the pipeline’s twelve subcommands read a single post-publish metric, so the condition could come true unobserved. The instrument was forty lines; what was missing was any record that those forty lines were required. The first version of it then cried wolf 1.6 hours after publication, because the word “stays” in my own criterion had implied a duration that evaporated on the way into code.

devopsobservabilityaidebugging

My Instrument and My Falsifier Were Both Wrong on the Same Night

Chasing a nightly cron job that jumped from 40 seconds to 1,725 seconds, I built both a diagnostic instrument and a pre-registered falsifier for the last surviving hypothesis — and on the first real night, both looked healthy while both were quietly wrong.

devopsdebuggingtestingai

A File-Based Work-Bus for Orchestrating a Fleet of Agent CLIs

Coordinate independent agent CLIs without LangGraph or a message broker: atomic Task/Result files, capability-based routing, absent-worker skip for graceful degradation, and a typed claim contract on the bus.

orchestrationmulti-agentLangGraph alternative

Our Status Column Said 30 Waiting. Six Were.

A publishing ledger kept every promoted item marked queued because the publish path never advanced the status. Twenty-four files were already published; binding the ledger update to the successful file move repaired the drift and restored the real six-item runway.

state integritypublishing pipelinepostmortem

The Scary Metric Was Wrong, the Audit Still Paid: A 21-Agent Sweep of My Claude Code Fleet

An efficiency audit found a silent cost regression, a cache-invalidation trap, a pricing cliff — and a terrifying "12% task completion" that turned out to be benchmark contamination plus a schema misreading (real rate: 98.4%). Verify the metric before reacting; the false alarm's investigation still fixed three real defects.

observabilitymulti-agentpostmortem

The Proxy I Added to Measure Tokens Tripled Them

A local capture proxy — attached via the documented base-URL override — silently disabled my agent CLI's lazy-loading of MCP tool schemas, inflating every request roughly 3x (79,761 → 241,659 tokens). Three verifiers reproduced the inflated numbers exactly and the interpretation was still wrong; only a no-proxy control run found the real cause. The meter changed the bill.

observabilityllmmeasurement

Your Per-Edit Test Hook Is the Cost You Can't See

A PostToolUse hook that reran a whole test file after every single-file edit was invisible to tool-call audits because a passing run produced no output, and it broke multi-file changes on purpose by scoring their still-incomplete first half as failure until the trigger moved from the editor's per-edit event to the author's end-of-turn signal.

testingautomationaidevops

The Key's Owner Wasn't the Spender

A cloud bill kept climbing and I blamed the CLI tool I was actively using — the real spender was a metered key sitting in my shell profile, silently inherited by two tools I never suspected.

aidevopsdebugging

The Fix Was Committed. The Old Value Kept Running.

I deleted three ambient API keys from my shell profile and confirmed they were gone with a clean-environment test. A tool reconnected minutes later and registered eight providers with one of the keys I had just removed.

devopsdebuggingprogramming

The Quota Said 100% Used. Actual Demand Was 13%.

An accelerator quota read 100.47% used across four concurrent projects, so I wrote a priority table to ration it — a table with ranks and not one number in it. Three measurements later: rescoring never spent the pool, a "GPU" label billed 1,043 seconds to a run that never touched a GPU, and real demand was 13%. Price the operations before you write the policy.

cost accountingobservabilityresource allocation

My AI Subagent Faked the Verification Output I Asked It to Attach

A subagent reported 7 files changed with zero disk changes behind it, then fabricated the ls -la and grep -c proof demanded of it. The two distinct failure modes (fabrication vs silent stall), the landmark-file check run in the orchestrator's own process, and salvaging a non-writing worker by switching its output channel.

multi-agentverificationpostmortem

Web, SEO & AI Search

Google Can't Fetch Your GitHub Pages Sitemap, but Bing Can: A Diagnosis and Workaround Playbook

25 days of "Couldn't fetch" on a sitemap whose 289 URLs all return 200 — a documented GitHub Pages pattern, not a broken site. Reading crawl stats, the manual Request-indexing workaround (~10/day quota), the dead ends to skip, and why Bing quietly matters more for AI search.

SEOGitHub PagesSearch Console

Does Any AI Actually Cite Your Site? A Cheap Weekly Probe That Turns GEO Into a Number

GEO is unfalsifiable until you measure citations: a fixed set of user-shaped questions fired weekly at a grounded model, a deterministic owner-scoped match, and a ledger that error rows can't fake — plus when not to measure at all.

GEOAI searchmeasurement

Verify the Output Surface: How 19 Green Tests Shipped Nine Broken Titles for Nine Days

A crosspost pipeline with 19 green gate tests published nine articles whose titles were visibly broken on the live platform for nine days. Tests verify the payload you build, not what the other system renders — a pipeline isn't verified until you check the output surface itself.

testingpostmortempipeline

The Renderer Dropped What the Script Ordered. Every Check Watched the Script.

Two same-day bugs in a map-animation renderer silently discarded part of what the script ordered — a country vanished, a highlighted country never got painted — and every existing check passed, because every check watched the input, not the artifact.

testingpythondebuggingai

Shipping Solo Apps with AI

Why Your Vibe-Coded App Looks Worse Than the Showcases: A Forensic Audit

A 6-agent forensic audit over 92 of my own sessions answered "am I prompting wrong?" — partially yes (zero visual references, zero style tokens), but the dominant cause was silent infrastructure decay: exhausted generation credits quietly swapped in code-approximated shapes, a generation server was down with a required model file missing, and a ready asset pipeline was never invoked for six-plus weeks.

vibe codinggamedevaudit

Doubling the Volume Didn't Fix It. The Two Events Landed on the Same Frame.

A stamp landing and a fill-complete confirmation sound fired on the same video frame, and neither event felt like it happened. Louder audio and bigger motion wouldn't have fixed it — a 0.35-second delay that split the two into separate beats did, immediately.

uxvideoanimationdesign

The Dead Space Wasn't a Config Miss — imshow Was Silently Reshaping the Axes

Map size varied fourfold across episodes rendered by the same code with the same settings. The composition config everyone had been tuning was innocent: one ax.imshow() call without an aspect argument was collapsing the axes to equal aspect on every scene, and the codebase had already measured that symptom and built a workaround around it.

pythondebuggingdatavizvideo

Government Open-Data APIs: Every Guess I Made Was Wrong Until I Probed It Live

Building a travel app on Korea's open-data portal: a documented-looking op name returned 500 (the real one returned per-gate passenger counts, not the grade field I'd invented), a sibling dataset 404'd because approval is per-dataset, a discarded dataset left a 401 red herring on the wrong gateway, and one API's airport parameter means the other end of the flight. Live capture is the only ground truth.

open dataAPIdegrade path

The AI Can't See What It Drew

My app mascot's arms rotated from the fingertips — invisible in code review, obvious in one render. Three structurally different variants instead of tint tweaks, the grep that saved a parameter used by 8 call sites, pre-registered design falsifiers checked at real sizes, and the render-first loop that fixes AI-drawn UI.

swiftuivibe codingdesign

The Assert Counted 100 Dots. The Screen Showed Two.

A statistics short's scene code passed every automated check — count, constants, margins, exit code — and the render showed 2 of 100 dots. Closing the gap took two more rounds, including a pixel check that caught a real defect then passed a 10.5-second hole anyway.

pythontestingdebuggingai

Three App Store Connect API Hard Limits That Only Bite at a Fast Release Cadence

A 20-minute JWT cap that 401s perfectly valid signatures, one app version in flight (409 STATE_NOT_SUITABLE), and a 2-in-flight/5-total review-submission ceiling with undeletable orphans (DELETE 403, PATCH 409 — web UI cancel or 7-day expiry only). The two-call pre-flight that avoids all three.

App Store ConnectiOSAPI

Unit Tests Passed. The Feature Never Ran. Three Times in One Session.

Three features, each with dedicated passing unit tests, none of which ever executed in the live app. One was broken by a merge that dropped two call sites; one existed only inside preview blocks; one was reported unwired in a line that got buried. Component tests are blind to wiring, and the shared root cause was a default value that removes the compiler's call-site audit.

testingwiringAI codegen

Grep won't find your dead gates. A fill-rate query will.

The predecessor note diagnosed three dead features. This one is about finding the rest: a fill-rate query run across seven projects, why the defect lives at the column rather than the feature, and a fourth kind of dead gate where the wiring was correct all along and the value still never arrived.

testingarchitecturedatabase

A Check That Has Never Run Is Not Passing

An enactment rule checked video shot contracts for self-contradiction and had never once fired — not because nobody called it, but because the field it read had no producer anywhere in the repository. A retroactive dry run then showed the rule's premise was wrong too, zero true positives across every contract it could evaluate.

testingdebuggingsoftwareengineeringai

Deprecation Doesn't Reach the Copies

A threshold got overturned by its own counterexample, then quietly re-derived and pasted into a different rule a week later. About three months passed before an audit noticed the copy had never died.

aiarchitectureprogrammingdevops

The Scheduled Step Failed on Night One. The Heartbeat Stayed Green.

The inverse of the note above: grep finds the call site, the scheduler entry exists, running the script by hand works — and the step still never ran, because launchd hands jobs a minimal PATH under which the wrong Python resolves. A correctly fail-soft design absorbed the failure while the heartbeat kept reporting healthy. Where a step's failure state has to live so the monitor already looking can see it.

devopsmonitoringscheduling

The Guard Passed on an Empty Table

A third kind of quiet check, after the two above: this one was wired in, ran to completion, and did not die — it returned PASS because the set it was checking was empty. The guard inserted its own probe row before asserting, so it stayed green through two runs where the layer it protected had produced nothing. Four instances of the same shape in one day, and the only check that caught any of them carried a population lower bound.

testingdatabasedevops

Your Checker Returned Zero. Four Times, Mine Was Just Looking at Less.

A fifth shape, and the one that needed no breakage at all: the population was fully present and every check ran to completion, but each instrument's aperture was narrower than the thing it reported on. A lenient parser said 180/180 where a strict one said 174; a checker that only knew one heading wording, then the identical hole in its own frontmatter scan. The detector I threw away is the important one — it failed a positive control, and a false negative is the failure mode that never argues back.

testingverificationstatic analysis

A Detector That Never Fires Scores Perfect on False Positives

Three attempts at an overlap detector for rendered video frames failed the same hidden way, and the fourth split in two — one predicate got wired into the gate, one didn't. The split turned on whether each could be made to fire on a known-bad frame, not on false positives.

testingpythondebuggingai

Your Verification Tool Reports What It Saw, Never Where It Didn't Look

The aperture problem again, but stacked three deep under one green checkmark. Five videos cleared a twelve-item gate and shipped; a later audit found four defects. 45% of what was on screen emitted no event, so the "more precise" scan I proposed would have missed both defects that motivated it. Layer two was worse — I cleared a real bug by reasoning from an event's name, and a summarizing fetch tool later fed me a false premise assembled from two true sentences in different sections.

testingverificationsamplingai

The check that cannot fire

A QC harness passed all 13 synthetic fixtures and broke on 5 of its first real inputs. Every root cause was the same shape — a threshold expressed as an absolute constant unrelated to the scale of the content — and the fix that made it 50x more sensitive kept every existing fixture green.

testingpythondebuggingengineering

The negative control that tested the wrong field

A round-trip loader's byte-comparison check turned green to red exactly on cue, but the mutation that flipped it touched a field with no bearing on the property the check existed to protect. Finding the real invariant took a second, co-designed mutation — and the first one stayed in the suite anyway, because it proved something the second one couldn't.

testingpythonverificationdebugging

The Known-Good Sample Was Not Known-Good

I derived a threshold from measurement instead of guessing, and the numbers looked clean — zero overlap, a 33x gap between the clusters. The sample I had labelled "known good" was one of the bad ones, so the line landed above the only failure band that mattered, and the backstop passed the exact class of failure it existed to stop.

testingverificationdebugging

The null result belonged to the other hypothesis

An experiment came back "identical, frame for frame," and I filed it as confirmation that the empty frames were unavoidable geometry. My hypothesis had predicted a change; the competing one had predicted exactly this. The real cause was an overshoot constant that was 3% of the distance travelled rather than 3% of the destination — invisible until a 46x zoom made it 136% of the frame it was overshooting.

debuggingpythontestingverification

Your validator must measure what you ship, not what you loaded

An honesty gate for a map-comparison renderer reproduced all four hand-computed golden vectors to four decimal places, then rejected a video that had already shipped and was actually honest. It was measuring raw source geometry the renderer never draws — and fixing that took the device from "honest only in limited cases" to 98.1% of 6,478 country pairs.

testingpythonverificationdebugging

Your Report's Numbers Are Computed. Its Sentences Are Not.

In a generated report, the counts came from the data and the prose came from string literals. Six sentences ended up contradicting the numbers printed beside them — and the checker I wrote to catch that passed the exact bug it was built for.

aitestingdevopsarchitecture

An Error Inside HTTP 200 Poisoned My Cache: Why response.ok Is Not a Success Check

An upstream reported throttling as HTTP 200 with an error envelope, so a rate-limited response parsed as a legitimately empty table and got memoized — serving zero rows long after the upstream recovered, with a completed walk and silent logs. Success is a verdict on the body schema, not the status code, and the cache write has to sit downstream of that verdict.

APIcachingerror handling

Exit 0, Empty stdout: the Quota Died on stderr

A subscription CLI hit its usage limit, wrote nothing to stdout, put the real error on stderr, and exited 0 anyway — exactly the shape of failure that any dispatcher checking only the exit code will log as success.

aidevopsdebugging

CSS Doesn't Throw: One Mistyped Comment Closer Silently Ate 15 Lines of My Stylesheet

A layout fell apart while 481 tests stayed green and the missing rules sat in the file, correctly written. A comment closed with Jinja's #} instead of */ made the parser consume seventeen lines to the next real closer. CSS has no fatal parse errors by design, so a linter cannot catch it — the fix that mattered was two assertions guarding the whole failure class.

CSSsilent failureguard tests

The Edge Cache That Never Served a Byte: Verify Cache Hits by Timing a Warm Call

The design record, the code and the response headers all said the endpoint cached at the edge. The first test that actually timed a warm call found it re-walking all 29 upstream pages at 2.9s against a 0.16s expectation — the cache API is a documented no-op on that hostname. Nothing broke, because the spend circuit breakers underneath were absorbing the load the cache was credited with removing.

edge cacheverificationserverless

macOS & Debugging

Compress a PDF on Mac with Preview: Check the Small Print Before You Send

A local macOS Preview test compares PDF size reduction with vector-text and image-only pages, then gives a safe check-before-send workflow.

macOSPDFPreviewEnglish

Mac PDF 용량 줄이기: 미리보기로 압축하고 작은 글씨 확인하기

macOS 미리보기의 Reduce File Size를 합성 벡터 텍스트와 이미지 전용 페이지에서 측정하고, 보내기 전 확인 순서를 정리했다.

macOSPDF미리보기한국어

The Process Check That Could Never Fire

Three process-existence checks in one live session turned out to be structurally unable to ever return true — an exact-match pgrep against a display name instead of a binary name, an automated watcher that inherited the same defect, and a memory preflight that measured itself with a different formula than the gate it was supposed to predict. A negative like that reads exactly like the normal, boring, correct state.

debuggingmacOSbashdevops

macOS: nslookup Works but curl and Python "Could Not Resolve Host" — the mDNSResponder Zombie

When nslookup resolves but curl/pip/Python fail, the mDNSResponder daemon is in a non-responsive zombie state. The two-DNS-path diagnosis, the weakest-first fix, and why long-running agent/MCP boxes trigger it (measured: 30+ long-poll connections → 77% CPU).

macOSDNSdebugging

When a Site Blocks Your Scraper, Read the Browser Tab You Already Have Open

For a personal tool, the way past robots.txt, bot detection, login walls, and JS-rendered SPAs isn't a better headless scraper — it's a ~40-line AppleScript/JXA bridge that reads the DOM out of the authenticated Chrome tab you already have open. Why it sidesteps every wall at once, and its honest read-only, single-machine limits.

web scrapingmacOSautomation

The Guardrail Has to Be Code: How a Runaway Local LLM Corrupted APFS and Bricked a Mac Mini

A background LLM server loaded models onto a nearly full disk; unified memory overflowed, swap failed, and APFS metadata corruption left the machine unbootable for a day. The postmortem, the five-layer code-level hard block, and the operating rules for 24 GB unified memory.

macOSpostmortemlocal LLM

The Guardrail Pointed at a File That Never Existed

The sequel to the note above, from the other direction: here the fix for a rule violation was another rule, and the same failure came back four days later. Three indicators were at zero the whole time — the enforcement mechanism the document cited had never been built, the project had no hooks, and the pinned file had been re-read zero times. Plus the part nobody checks: the account of what went wrong was itself wrong, and it leaned toward the less-bad story.

postmortemenforcementai agents

The Gate Pinned a Model That No Longer Exists

An adversarial-review gate that forced every trading thesis through an outside model turned out to hard-pin that model by version string. The audit found both the pinned primary and its emergency backup already dead.

aillmarchitecturetesting

Why My Correct Config Value Was Being Ignored

An MCP server sat idle reporting itself unconfigured while the correct key waited in its own .env. An empty placeholder for the same key in a higher-priority settings layer was shadowing it — load_dotenv(override=False) treats an already-set empty string as defined and won't overwrite it. The fix was deleting the empty binding, not changing how the loader resolves precedence.

debuggingpythonconfiguration
Browsing? Every note here is a failure I actually hit and had to fix — agent-fleet operations, harness bugs, and the measurement that proved the fix. All of it is free and none of it is gated. Get new notes by email.
← hexisteme home · about · editorial policy · privacy · contact · CC-BY 4.0