Build LogContent Pipeline
#01
2026-07-265 min read

Eight clusters triaged, zero published: why autonomous content cadence fails silently

The UK Calculators content pipeline ran three clean cron exits and published nothing for three weekdays. No errors, no alerts, just absence. Three weeks of daily runs showed the failure mode is not bad drafts. It is a gate that rejects everything differently each day, and a cadence monitor that asks the wrong question.

Read post
Build LogUK Calculators
#02
2026-07-265 min read

The cron kept drafting mortgage because gov.uk wasn't in the source set yet

For five days, the cron produced news-cluster drafts and operators shipped gov.uk regulatory pillars by hand. Day 6 changed one thing: gov.uk Search API sources entered the polling loop. Two data-pegged pillars from a single cycle followed immediately.

Read post
Build LogLearning Hub
#03
2026-07-265 min read

The in-chapter TOC needed live JavaScript. It still got a mockup first.

The captainrandom learning hub navigation retrofit ran five phases. Every one went through the UI gate — interactive approval mockup before production code. The most interesting case was P4: the subsystem's only client-side component, with a live IntersectionObserver scroll-spy in its mockup, still approved before a line of React was written.

Read post
Build LogPrivacy
#04
2026-07-265 min read

The privacy work isn't on the /privacy/ page

The /privacy/ page went live in June and covers what it covers. The actual privacy work on this site happened in a data-locality choice, a brand-separation rule, and a username leak in published MDX. Only one of the three announced itself.

Read post
Build LogUK Calculators
#05
2026-07-255 min read

10 of 13 sentences made it. The verifier caught the rest before they reached a pillar page.

The June 30th cron produced a mortgage rate-spike draft grounded in April 2026 data. Ten of thirteen sentences passed. The three that didn't never reached a pillar page — and the next two days showed why that distinction matters at publishing scale.

Read post
Build LogContent Pipeline
#06
2026-07-256 min read

14 days of daily publishing: the three failure modes I hadn't designed for

A 14-day publish cadence on UK Calculators surfaced three failure modes: title-mangling produces permanent ugly slugs, zero-draft mornings expose the absence of a fallback queue, and triage without memory republishes the same cluster it shipped the day before.

Read post
Build LogSEO
#07
2026-07-255 min read

AdSense low-value rejection: thin pages, empty hubs, and six SVG diagrams

UK Calculators was rejected for low-value content on 10 July — ads.txt was authorised, so this was purely a content-quality judgement. Three concrete moves addressed the specific inventory-value criteria: expanding thin calculator landings, adding SVG diagrams across the pillar estate, and populating empty hub pages the rejection identified.

Read post
Build LogUK Calculators
#08
2026-07-255 min read

The E2E suite billed 1,130 minutes to test a page that never existed

A Playwright suite on a private repo ran 69 times in three weeks, failed 61 of them, and billed roughly a thousand minutes doing it. The root cause was three mistakes stacked on top of each other, and the deepest one was mine: I did not know GitHub Actions had a bill.

Read post
Build LogLearning
#09
2026-07-245 min read

The backlog called it a content gap. It was navigation.

Completing an eight-chapter course on the learning hub felt like progress. Then I looked at what had actually moved the needle — track sections, prerequisite chips, and a JSON-LD breadcrumb. The backlog had been mis-filing the bottleneck for months.

Read post
Build LogLearning Hub
#10
2026-07-245 min read

The search index built in three seconds. Five phases made that possible.

Pagefind took an afternoon to wire up. The navigation phases before it took a week. A search index returns what’s there — and what needed to be there first was structure.

Read post
AdSenseSEO
#11
2026-07-235 min read

AdSense readiness: the checklist caught one gap, the reviewer found another, the sweep found a third

Seven out of eight on the automated readiness audit, then rejected for low value content anyway. The fix required three rounds: media diversity closed before submission, hollow hub listings after rejection, and a site-wide sweep that stripped fabricated trust signals the structural checklist had no way to catch.

Read post
Build LogAdSense
#12
2026-07-235 min read

Google's AdSense reviewer checklist returned 7 of 8 green. Format diversity was the one that counted.

Running Google's reviewer checklist against UK Calculators returned 7 of 8 green. The one red item was format diversity: zero of 38 articles had any embedded visual content. Eight days after submission, rejected for low value content — a checklist score doesn't carry item weights, and format diversity was the one Google's reviewer weighted most.

Read post
Build LogUK Calculators
#13
2026-07-235 min read

The cron produced zero drafts. That was the correct answer.

Four mornings into a 14-day operator-publish sprint on UK Calculators, the pipeline ranked 150 clusters, fetched candidates, and produced nothing. Not a failure. A signal that the ground-truth layer, not the LLM, is the binding constraint in a pipeline built on live gov.uk sources.

Read post
Build LogAI Tools
#14
2026-07-225 min read

Fifteen claim blocks and a zero-draft cron: the cost of grounding a content pipeline in gov.uk

Hand-curated gov.uk claim blocks stopped the ukcalculators drafter fabricating figures. Three days after the first clean pillar shipped, the cron fired on time, ranked 150 clusters, put mortgage at the top — and produced nothing. That was the gate working correctly.

Read post
Build LogLearning
#15
2026-07-225 min read

The cheapest phase in a seven-phase plan was also the highest-leverage one

Prerequisite chips in the learning hub — three words, one arrow, no JavaScript — outperformed every other navigation phase by the only metric that matters at the chapter level: whether a reader knows what to read first. The evidence is what the other six phases cost by comparison.

Read post
SEOObservability
#16
2026-07-225 min read

The eight-pillar map closed in three days. ga-telemetry and gsc-telemetry are why.

Phase 1.6 shipped two observability skills on 20 June: ga-telemetry and gsc-telemetry. Six days later the eight-pillar topic-authority map was complete. The link is an operator loop built on next-morning indexation signal.

Read post
Build LogTypeScript
#17
2026-07-215 min read

`ignoreBuildErrors: true` kept the type checker quiet. Turning it off found twelve product bugs.

UK Calculators had `strict: true` in tsconfig and `ignoreBuildErrors: true` in next.config.mjs. The two settings coexisted for months. One afternoon removing the flag surfaced twelve masked type errors on a YMYL money site where wrong numbers carry real consequences.

Read post
SecurityDevOps
#18
2026-07-216 min read

Scope the MySQL user first: the newsletter DDL as a security boundary on cPanel

On shared hosting, you don't control the firewall or the infrastructure. What you do control is which privileges the MySQL user holds. Scoping it to the newsletter schema alone made a compromised endpoint's blast radius structurally finite — not as a mitigation layered on top, but as a property of the design.

Read post
Build LogContent Pipeline
#19
2026-07-216 min read

Zero drafts at 07:00: build the gate, not the prompt

The 29 June cron ran every stage correctly and produced nothing. Haiku underfired on claim-extraction, the pipeline accepted the shortfall without raising an error, and the log showed a clean exit. The fix was a corrective stage that detects the count failure, reruns with constrained parameters, and marks the run failed if the second attempt also falls short. Six pillars shipped in the three days that followed.

Read post
Build LogPipeline
#20
2026-07-205 min read

Ten cycles, one ready draft: the pipeline was consuming its failures

Between 30 June and 13 July, ten cron cycles produced one ready draft and zero auto-publishes while the skipped counter climbed from 2 to 7. The drafter was not stalling. It was treating failed attempts as permanent completions, and only heartbeat visibility on ready-draft count made the dead zone visible.

Read post
Build LogContent Pipeline
#21
2026-07-205 min read

The cron exited clean. There were no drafts.

Two zero-draft mornings out of four cron firings across 29 June to 2 July, both exits clean. The failure was Haiku's claim extraction underfiring one stage before draft: structurally invisible, no error, no warning, cron returns success.

Read post
Build LogContent Pipeline
#22
2026-07-206 min read

The cron fired at 08:22 and drafted nothing — scheduling is the easy part

On 2 July, the pipeline ran on time, ranked 150 clusters, fetched candidates, and produced zero drafts. The scheduler worked. The grounding step didn't. Automating gov.uk pillar articles forces a distinction that took a zero-drafts morning to make explicit: cron reliability and content freshness are different problems, and only one of them is solved.

Read post
Build LogLearning Hub
#23
2026-07-195 min read

Six navigation phases, one client island: why the keyboard audit took half an hour

The learning hub's navigation plan ran six phases. Five shipped as pure RSC; the server knew the URL, and that was enough. The in-chapter TOC with IntersectionObserver scroll-spy was the only genuine client requirement, and keeping the client surface at one component made the accessible-by-default story apply to everything else.

Read post
Build LogPipeline
#24
2026-07-195 min read

Three weekdays, zero publishes: draft.py was consuming its own failures

Between 7 and 9 July the UK Calculators cron fired on time, triaged candidates, and assembled source packs. It published nothing. Across ten cycles, skipped climbed from 2 to 7 before the cause was found: draft.py was writing failed-* markers to the same index it used for successful consumption, permanently locking out any topic that had ever failed a draft attempt.

Read post
AdSenseSEO
#25
2026-07-185 min read

AdSense said 'low value content'. Mapping that to actual pages took a day.

The ads.txt was authorised. The rejection still came back 'low value content' on 10 July — a content quality judgement that maps to three specific gaps: thin surfaces, empty hub listings, and zero images across 38 articles. Passing the re-review required treating Google's inventory-value policy as a content brief, not a configuration checklist.

Read post
Build LogContent Pipeline
#26
2026-07-185 min read

Five days, ten operator publishes, two cron drafts: where the ukcalculators pipeline actually breaks

Running a 14-day pillar schedule with a parallel operator-publish path made the bottleneck legible: the cron fires on schedule, triage completes, 150 clusters rank — then the ground-and-extract stage drops everything silently. The schedule is not the problem.

Read post
Build LogContent Pipeline
#27
2026-07-186 min read

Ten of thirteen: why verification without correction is just expensive triage

The morning cron produced a draft with 10 of 13 sentences passing the verifier. Without a corrective step, that's a triage ticket, not a publish. Four days of cron output showed the rescue pattern fires once in four — and what covers the other three.

Read post
Build LogContent Pipeline
#28
2026-07-175 min read

150 clusters ranked, zero drafted: ground attrition is the load-bearing constraint

Five days of autonomous publishing logs made the pattern clear. The cron fired on schedule every morning. Ground attrition killed the drafts before the drafter ran. One usable cron draft across five days; ten articles published via a different route entirely.

Read post
Build LogNavigation
#29
2026-07-175 min read

Seven navigation phases. The prerequisite chips encoded the one thing the others couldn't.

The learning navigation spec ran seven phases from foundational structure to site-wide search. P5 — prerequisite chips, a static 'Read first' link at each chapter head — was the smallest implementation. It was also the highest return: every other phase encoded page structure, and P5 encoded reader intent.

Read post
Build LogSecurity
#30
2026-07-176 min read

Six PHP classes, no Composer: a cPanel newsletter backend with enumeration-resistant auth

The captainrandom.co.uk newsletter backend runs on a cPanel shared host with zero framework and no Composer. Six small PHP classes, around 600 lines, and an eight-stage subscribe pipeline that tells the caller nothing about whether an email address already exists.

Read post
Build LogLearning Hub
#31
2026-07-165 min read

Pagefind shipped last. The prerequisite chips had already closed the harder problem.

The learning hub's navigation plan ran seven phases and ended with site-wide Pagefind search. The highest-leverage phase was five: a three-word chip at each chapter head pointing to the one thing to read first. By the time search shipped, most readers who needed it no longer did.

Read post
Build LogContent Pipeline
#32
2026-07-166 min read

The cron said zero twice and ten-of-thirteen once. Every answer was correct.

Five mornings of cron firing produced two zero-draft rejections, one partial-pass, and six operator-path publishes. Zero drafts is not a pipeline failure. It is the verifier doing its job when the inputs do not warrant a draft.

Read post
Build LogLearning Hub
#33
2026-07-165 min read

The navigation plan shipped on Pagefind. Prerequisite chips were the higher-leverage fix.

Six phases of navigation work shipped on the learning hub in July. Pagefind — site-wide search — closed the programme. Prerequisite chips, one phase earlier, delivered more navigability per line of code by firing at orientation time rather than recovery time.

Read post
Build LogLearning
#34
2026-07-166 min read

The read-first chip outperformed the TOC, track sections, and site-wide search

The learning hub navigation programme ran six phases across two days: track sections, a scroll-spy TOC, prerequisite chips, and site-wide Pagefind search. The smallest phase shipped fifth and delivered more navigability than all the rest combined. The structural reason was there in the spec before the build started.

Read post
Build LogAdSense
#35
2026-07-155 min read

AdSense rejected the site. The ads.txt was fine.

The Google AdSense verdict for UK Calculators arrived 10 July: rejected, “Low value content.” The ads.txt was authorised. The review had nothing to do with technical setup — Google was auditing editorial depth, and the /resources hub pages didn’t pass.

Read post
Build LogPHP
#36
2026-07-155 min read

I hand-wrote the newsletter backend in PHP. The threat model is the code.

The captainrandom newsletter subscription backend is 600 lines of PHP, six classes, no framework, no Composer. Every security decision — rate limits, honeypots, time-traps, token hygiene — lives in the endpoint files, readable end-to-end in one sitting. That's the trade: no ecosystem, but a threat model you can hold in your head.

Read post
Build LogLearning
#37
2026-07-154 min read

Seven phases in. The chip at the chapter head was still the highest-leverage fix.

The learning hub navigation programme shipped complete last week: seven phases, P0 through P6, from breadcrumb to site-wide Pagefind search. Improving on the earlier post that identified the prerequisite chip as the spec's highest-value navigability fix — having shipped P4's IntersectionObserver scroll-spy and P6's full search index, the designation holds. Here's what shipping the full programme makes visible.

Read post
Build LogLearning Hub
#38
2026-07-156 min read

The navigation spec pre-ranked prerequisite chips over search. Six phases later, that held.

The conventions.md backlog called prerequisite chips at the chapter head the single highest-value navigability fix before any code shipped. Pagefind search and an IntersectionObserver right-rail TOC both landed in the same programme. The ranking held. This is why.

Read post
Build LogLearning Hub
#39
2026-07-146 min read

Prerequisite chips, scroll-spy TOC, and Pagefind: the trio that closed the learning hub nav spec

Seven phases of navigation work landed on the learning hub over two days. Phases P0 through P4 were infrastructure. P5 and P6 changed what the property felt like to use — and both were in the spec from day one.

Read post
Build LogUK Calculators
#40
2026-07-145 min read

The cron ran clean and drafted nothing: eight pillars in five days named the extraction bottleneck

Five days into a 14-day operator-publish sprint, the cron fired on-time every day and produced two useful drafts — one of which recycled yesterday's ground. Improving on the quality-gate diagnosis from the inheritance tax piece, this sprint isolated an earlier failure: claim extraction stalls before the drafter gets a turn.

Read post
Learning HubNavigation
#41
2026-07-145 min read

The highest-leverage navigation fix was a conditional on a frontmatter field

conventions.md ranked the N1 prerequisite chip as the single highest-value navigability fix before any phase of the learning-hub navigation plan shipped. After a scroll-spy TOC, hub track sections, and site-wide Pagefind search, the ranking holds. Reader-orientation at the chapter entry-point outperforms retrieval mechanics for an audience that doesn't know what it doesn't know.

Read post
Build LogSearch
#42
2026-07-133 min read

A static site has no server to search. So I indexed the output instead.

There is no query endpoint on a statically-exported site, no database, nothing to ask at request time. Full-text search still works, because you index the HTML the build already produced.

Read post
Build LogAnalytics
#43
2026-07-133 min read

GA4 saw nothing for four days. The fix was gated behind the consent it was meant to make optional.

The Consent Mode v2 default that was supposed to fire for every visitor lived inside a function that only ran after someone clicked Accept. So first-time visitors loaded no analytics at all, and GA4 recorded nothing.

Read post
AnalyticsGA4
#44
2026-07-135 min read

GA4 went dark for four days. Both fixes were right. One was in the wrong place.

Two PRs, each diagnosing a real fault, and GA4 still flat four days later. The problem wasn’t whether the consent signal was present — it was where in the document it lived relative to gtag.js.

Read post
Build LogArchitecture
#45
2026-07-133 min read

One hardcoded album was fine. The tenth would have broken the page. So /creative stopped hardcoding anything.

The first version of the creative hub had all ten NAPA tracks written directly into the page component. That works for one album. It falls apart at ten. The rebuild made the page a reader of files, not a holder of content.

Read post
LearningNavigation
#46
2026-07-136 min read

Prerequisite chips were the highest-leverage fix. They shipped fifth.

The navigation spec for captainrandom’s learning hub named the N1 prerequisite chips the single highest-value browsability improvement. They shipped in Phase 5 of 7. Course sidebar, in-chapter TOC, prerequisite chips, and site-wide Pagefind each close a different kind of lost — and the order they can ship in is a dependency graph, not a priority list.

Read post
SecurityBuild Log
#47
2026-07-136 min read

The confirm link token was in five places before the subscriber clicked it

Building newsletter confirm and unsubscribe handlers revealed a leak surface most developers overlook: tokens passed via GET end up in browser history, Referer headers, and server access logs before any mutation happens. The fix is an interstitial — show a page on GET, mutate only on POST.

Read post
Build LogDocs
#48
2026-07-136 min read

The roadmap was silently gone: four documentation layers and why none of them overlap

Six weeks after captainrandom's first devlog entry, a session to document the /learning/ work surfaced three problems. The most instructive: the roadmap had gone missing without raising an error anywhere. That is what four layers is for.

Read post
Build LogSEO
#49
2026-07-133 min read

The tag on 73 of 74 posts told me nothing about what relates to what.

Building a 'related posts' block surfaced a problem that had nothing to do with rendering: the tag on nearly every article carried no signal, and letting it count made everything related to everything.

Read post
Build LogAI
#50
2026-07-133 min read

The video spec had a voice-clone bake-off. The same day, I cut generated voice entirely.

The one open decision in the video-pipeline spec was which synthetic voice would narrate: a clone of mine, or a premium API voice, picked by ear. I deleted the question instead of answering it.

Read post
Build LogSEO
#51
2026-07-123 min read

Every route but the blog previewed blank on WhatsApp. The og:image default was missing.

Blog posts set their own share image, so links to them looked fine. That masked the fact that every other route on the site emitted no og:image at all — invisible until someone shared one.

Read post
Build LogContent Pipeline
#52
2026-07-126 min read

Four cron zeroes in five mornings. Eight articles shipped by hand. The pipeline problem isn't the scheduler.

Five days into a fourteen-day publishing sprint on UK tax calculators, the scheduler fires within a minute of its window every morning. Automated drafts produced: two, one a duplicate cluster. Gov.uk cooperates. The bottleneck is claim extraction and cluster survival.

Read post
Build LogContent Pipeline
#53
2026-07-126 min read

What shipped on 2026-06-25 wasn't T-004: the verifier is the pipeline's real editor

T-004 was next in the topic-authority backlog — NRB and RNRB explainer, score 11. Two operator-driven publishes on 2026-06-25 shipped IHT rates and property tax reform instead. The backlog had an opinion; the verifier had authority.

Read post
Build LogAI
#54
2026-07-103 min read

The voice-check agents passed two chapters. A three-line recount proved they couldn’t count.

An ultracode workflow’s voice-check agents passed two course chapters as within the em-dash budget. A three-line Python recount found both over. A model can’t reliably count its own tells.

Read post
DocsProcess
#55
2026-07-066 min read

The process changed. The docs didn’t. The fix was a folder.

Three times in the captainrandom repo, documentation drifted from actual practice. Each time the fix was the same: a dedicated folder with its own PRD, roadmap entry, and devlog trail — not a patch, but enclosure.

Read post
Build LogiOS
#56
2026-07-055 min read

The back-nav went to Accounts. It should have gone to the calendar.

Weeks of Accounts build work passed SwiftUI preview on every check. The first hands-on device install found gaps the simulator had never reported. Round two found a navigation bug — Back from Day view landed in Accounts, not the calendar — that the simulator had never seen.

Read post
VisualiserAudio-Reactive
#57
2026-07-055 min read

The spring panorama has winter underneath it: audio-driven temporal layering

Two panoramas, identical dimensions, stacked front-to-back. The spring layer carries a radial cutout whose radius is driven by bass amplitude. When bass hits, winter shows through. The background is not a backdrop — it is a temporal device indexed to audio rather than time.

Read post
SEOBuild Log
#58
2026-07-055 min read

The ultracode audit was clean. Google still hadn't found the pages. The fix was six in-body links.

Five legal pages and /stamp-duty-calculator were returning HTTP 200, index/follow, self-canonical — and still showing 'URL is unknown to Google' in Search Console. A multi-agent ultracode review ruled out every technical blocker. The answer was the link graph: footer-only pages don't get crawled.

Read post
Build LogLearning Hub
#59
2026-07-055 min read

Three words and an arrow: the learning spec's highest-value navigability fix

Seven phases of navigation work shipped across the learning hub. The spec rated P5 — a row of prerequisite chips at the chapter head — highest-value for navigability. It was the only phase designed to answer a question the reader didn’t know they had.

Read post
Build LogCreative Coding
#60
2026-07-045 min read

A hole in spring: the bass-masked radial portal that skipped the shader

Two panoramas at identical dimensions, one layered in front of the other. Cut a radial hole in the front layer, drive its radius with bass energy, and winter is visible through spring. No shaders, no post-processing pipeline — just winding-order arithmetic on a canvas clip path.

Read post
Build LogCreative Coding
#61
2026-07-046 min read

Bass as a window: the low end punches a hole in spring and shows you winter

Adding a winter panorama behind the spring layer did nothing until the spring canvas got a radial alpha hole driven by bass frequency. The moment that connection landed, the low end stopped being a brightness signal and became a literal window between seasons.

Read post
Build LogDevOps
#62
2026-07-045 min read

Four lines in a published article leaked my macOS username to the live site

PR #17 was a four-line diff across two files. One of those lines was in the body of a published article, rendering a real macOS username in the browser. The fix was substitution — but the pattern it revealed was wider: three surfaces in the same audit window, the same failure.

Read post
Build LogLearning
#63
2026-07-045 min read

We captured thirteen GCP screenshots in one sitting. The OAuth console had changed while we weren't looking.

Chapter 2 of the GSC + GA4 automation course needed thirteen screenshots of the Google Cloud project setup flow. The session that produced them found that the OAuth consent screen had been redesigned since the prose was written — and showed why that kind of discovery only happens in a live browser, not a mockup.

Read post
Build LogLearning
#64
2026-07-035 min read

Chapter 2 had thirteen screenshots and one OAuth rewrite. The three architecture decisions explain both.

The Google Cloud setup chapter of the GSC+GA4 automation guide forced three architectural calls before any screenshot was captured. Then Google redesigned the Auth Platform UI and the OAuth section had to be rewritten. This is what the decisions looked like at runtime.

Read post
SEOBuild Log
#65
2026-07-037 min read

Six YMYL pages were unknown to Google. The technical audit came back clean.

An ultracode review of five legal pages and the stamp duty calculator found no technical blockers — HTTP 200, correct directives, canonical self. The pages weren't stuck because of markup. They were stuck because Googlebot had no editorial reason to visit.

Read post
Build LogAccessibility
#66
2026-07-035 min read

The first visible change to /learning/ arrived after the tests, the breadcrumb, and the JSON-LD

P2 of the learning-hub navigation was the first thing a visitor could see. By the time it shipped, the repo already had 37 passing fixture tests, a semantic breadcrumb, and a data model — none of it visible. The spec changed what shipped first, which changed what was easy to skip.

Read post
Build LogCreative Tech
#67
2026-07-025 min read

Bass amplitude into a radial alpha mask: audio reactivity as compositing, not particle spawning

Most audio visualisers route frequency data into particle spawn rates. Routing bass amplitude into a radial alpha mask between two panoramas is a different model — one where the music reveals a scene rather than decorating it. This is audio reactivity as a compositing problem.

Read post
Build LogDVLAW
#68
2026-07-025 min read

I fixed four pipeline bugs in three days. The success rate was 20%.

On the morning of 2026-06-13, three articles were blocked or in trouble before 09:00. Working backwards from a 20% autonomous success rate across five slots revealed something individual fix sessions don't surface: every fix had left the adjacent failure mode intact.

Read post
Build LogPrivacy
#69
2026-07-025 min read

I patched the same privacy leak four times. The lesson isn't to be more careful.

Private repo names in a language stats page. A macOS username in a published plist example. A missing privacy policy when the newsletter went live. Four separate fixes, each reactive, each after deployment. Four is enough to name the pattern: the publish boundary has no scrubber.

Read post
Build LogContent Pipeline
#70
2026-07-015 min read

145 words shipped on inheritance tax. 949 words fixed it. The gate measured the wrong thing.

The operator-publish gate cleared 145 words on UK Inheritance Tax because word count was above minimum and the verifier passed. IHT is YMYL content. A same-day ultracode rescue to 949 words proved the gate needs a depth signal, not just a length floor.

Read post
SEOAdSense
#71
2026-07-016 min read

Eight pillars published. AdSense said low value content. The bottleneck was never volume.

Closing the 8-pillar map on 23 June was the point at which Phase 1.6's publish-volume theory ran out of runway. The AdSense low-value-content gate was already in place; more articles hadn't moved it. The real bottleneck is internal-link density and topic-cluster cohesion.

Read post
iOSSwift
#72
2026-07-015 min read

The check-in button opened a transaction form: how three device-QA bugs made bb-finance's Home gamification navigable

The three Home gamification blocks in bb-finance — Quests, Level, Streak — were pulling live data and doing nothing else. Tapping the Streak check-in opened the transaction form instead. Three bugs from the AnF device-QA round forced Phase N, which built the detail screens and routing that turned the blocks from decoration into navigation.

Read post
DVLAWBuild Log
#73
2026-07-016 min read

The substitute pool stole from future slots because slots didn't exist as rows

Phase B's autonomous publishing pipeline sat at twenty percent success. The substitute pool was recursing through future-scheduled rows to breach — and nothing in the data model could stop it because slots had no identity. Making the slot a first-class entity with explicit state transitions turned six log events into six queryable rows.

Read post
SwiftUIiOS
#74
2026-06-306 min read

Back from the day view landed on Accounts — the simulator had nothing to say about it

Phase O added a full-screen month calendar inside the Accounts tab, taking the navigation to three levels. Round-2 device QA found A8: tapping Back from a day view vaulted over the calendar entirely and returned to the Accounts screen. The simulator had approved the same flow without complaint.

Read post
Build LogDVLAW
#75
2026-06-306 min read

Correct answers, wrong questions: four DVLAW scope errors in 72 hours

Between 2026-06-10 and 2026-06-13, four DVLAW bugs caused cascading slot failures, auto-published style violations, and a near-duplicate article. None threw an exception. All of them were answering the wrong question correctly.

Read post
Build LogCreative
#76
2026-06-305 min read

The bass mask belongs on the front layer: that's what turns the background into a different season

Moving the radial bass mask from a dark overlay to the front panorama layer changes what the effect communicates. Previously the bass revealed texture through a luminosity window. Here it cuts a hole in spring to show winter behind it — a temporal portal, not an illumination effect.

Read post
Build LogPrivacy
#77
2026-06-306 min read

The identifiers I didn't know I'd published

Five fixes across /learning, /now, a published article, the privacy policy page, and a global pre-commit hook — all tracing back to the same root cause. Not tracking, not data harvesting. Just private names in places I'd stopped looking.

Read post
Build LogLearning
#78
2026-06-295 min read

Before the first word: three architecture decisions in an 8-chapter GSC and GA4 course

An 8-chapter guide to Google Search Console and GA4 automation forced three architecture decisions before any writing started: a throwaway GCP project per reader, Steps components over prose, and inline chapter links from day one. I made the first two immediately. The third I retrofitted.

Read post
SwiftUIiOS
#79
2026-06-295 min read

Calendar → Day → Back Landed on Accounts. The Stack Was Correct; the Model Wasn't.

A8 in the round-2 device QA pass: tapping Back from the day view skipped the full-screen calendar and landed on Accounts. The NavigationStack had done nothing wrong. The navigation model had no concept of levels.

Read post
SEOBuild Log
#80
2026-06-296 min read

My canonical tags were deindexing my own articles. GA4 had been right all along.

GA4 showed 2 events per seven days across a site with 70+ articles. The first instinct was broken tracking. The real cause was canonical tags instructing Google to ignore the pages meant to rank — a discovery collapse that looks identical to a measurement failure until GSC gives it away.

Read post
Build LogPrivacy
#81
2026-06-296 min read

The privacy policy was correct. The article body wasn't.

A production audit found the macOS username in a published plist example and private project names on two public pages. Neither would have been caught by a policy document. The fix was a pre-commit hook and an aggregation change — pipeline enforcement that runs whether the author remembers or not.

Read post
Build LogDVLAW
#82
2026-06-285 min read

Five Phase B fixes in 48 hours. They were all patching the same missing type.

Twenty percent autonomous success across five scheduled slots. The same breach shape surfacing twice from different audit trails. Five fixes shipped in 48 hours — and when the sixth investigation opened, the pattern became unmistakable: the slot had never been an entity.

Read post
Build LogCreative Coding
#83
2026-06-286 min read

Not a fade, a life: energy decay and perpendicular wobble in a music visualiser

The onset particles were launching correctly and dying identically. Tying an exponential energy decay to the perpendicular wobble amplitude was the difference between particles that travel and particles that live.

Read post
Build LogSEO
#84
2026-06-286 min read

One audit finding, eight chapters: closing content-5 with a hub instead of inline links

The SEO audit said to retrofit inline links across seventy articles. I built a guide hub instead, and the link-graph problem stopped being about retrofitting and started being about new direction.

Read post
Build LogCreative Coding
#85
2026-06-285 min read

The bass portal doubled as a scene swap. The hole geometry already owned the reveal.

A bass-driven radial mask opens a hole in a spring panorama to reveal winter behind it. When the track hits its midpoint, the same mask — scaled to frame-covering size — swaps the two scenes without a cut. The reveal mechanism was already running from frame one.

Read post
Build LogTesting
#86
2026-06-286 min read

The diff check passed forever. That was the bug.

A test that checked whether verify.py was modified by a wiring PR became trivially true the moment PR #43 squash-merged. Phase X.8 replaced it with replay hashes, pre-registered gates, and hermetic sabotage cycles — tests designed to fail when they should.

Read post
Music VisualiserCanvas
#87
2026-06-276 min read

Bass as a seasonal portal: routing the kick into a radial alpha mask

The captain-random visualiser stacks two panoramas: spring in front, winter behind. The spring layer carries a radial alpha mask whose radius tracks bass energy. When the kick hits, the mask opens and winter shows through; when the energy decays, spring closes back over it.

Read post
iOSSwift
#88
2026-06-276 min read

One PR, three game systems: why pure generators kept the ledger honest

Shipping streaks, quests, and levels as a single PR forced a specific architecture: pure generators with no side effects, persisted targets decoupled from quest logic, and celebration overlays computed after state transitions. This is the constraint that produced those decisions.

Read post
iOSSwift
#89
2026-06-275 min read

Real quests, broken buttons: how Phase C and N closed bb finance's behaviour loop

Phase C replaced mockQuests with a generator that reads real transaction history. Phase N found that the quest blocks were non-interactive labels and the streak's Check In button opened the wrong screen. Both sprints were necessary. Only together did they close the loop.

Read post
Build LogCreative Coding
#90
2026-06-276 min read

Spring became winter on the bass hit. That was the effect that mattered.

Three reactive effects were already live — bloom, particles, waveform — and the visualiser still read as a showcase. The portal changed that: a bass-driven radial mask cuts from spring into winter, and reactive opacity does something reactive motion cannot.

Read post
Build LogSEO
#91
2026-06-266 min read

Six pages Google couldn't find: telemetry ruled out the technical before we touched any code

The GSC digest showed six pages stuck at “URL is unknown to Google.” That specific status — not crawled and filtered, just never discovered — changed what we looked for first. Two stdlib-only telemetry skills made that diagnostic distinction available before we opened a single file.

Read post
iOSSwift
#92
2026-06-266 min read

The accessibility gate that made stacking five motion effects into one PR survivable

Phase D of the Cursed Energy DNA landed sigil rotation, energy pulse, claim spark, level-up celebration, and streak milestones in a single PR alongside three other features. Accessibility review was a non-event — not because the PR was small, but because every motion effect owned its own gate.

Read post
Build LogAnimation
#93
2026-06-265 min read

The centre of the portal was flat. Removing the glow layer fixed it.

A spring-to-winter temporal portal with a halfway scene swap had one visual problem: the centre read as dull against everything around it. The instinct was to add a brighter overlay. The fix was removing the one already there.

Read post
Build LogEditorial Pipeline
#94
2026-06-265 min read

The sabotage tests passed. The live cycle still found the bug.

Phase X.8 shipped with two hermetic sabotage cycles green. The first live run produced no article — not because the pipeline crashed, but because calculator_scores in ground.py was wrong in a way the fixtures had never exercised. Hermetic tests prove the logic path. Live harnesses prove the integration.

Read post
iOSSwift
#95
2026-06-254 min read

Five animations, five accessibility gates: what Cursed Energy Phase D cost to ship correctly

Phase D of the Cursed Energy design system added five animated effects to bb finance: sigil rotation, energy pulse, claim spark, level-up celebration, and streak milestone overlays. Every one is gated by the SwiftUI Reduce Motion environment key. Gating from the start rather than retrofitting later cost extra environment reads on every animated view. What it bought was a WCAG 2.1 AA clean bill before any user encountered the animations.

Read post
Build LogAutomation
#96
2026-06-255 min read

Phase 9 claimed self-driving overnight. The first five slots returned twenty percent.

Phase 9 described BBBrain's auto-pipeline as self-driving overnight delivery. Five scheduled slots later, the success rate was twenty percent — four cancellations, two architectural gaps in the publisher, and one duplicate that should never have queued. The rebuild was around explicit failure modes, not the happy path.

Read post
Build LogDVLAW
#97
2026-06-255 min read

The publisher cancelled the 12:00 slot. My recovery logic called the publisher again.

Queue id=37 was scheduled for 12:00 BST on 13 June. schedule_sweep fired publisher at 11:00:08Z, publisher cancelled the row, and Fix B (the SLA recovery layer) called publisher again. Recovery logic without a model of who holds the lock cannot distinguish a concluded failure from a recoverable one.

Read post
Build LogAudio
#98
2026-06-255 min read

Three effects, one envelope: how the bass signal became the nervous system of this visualiser

The neon bloom formula was written for one layer. Two days later, the same bass envelope was driving particle wobble and a radial time-portal. That convergence wasn't designed — it was pulled out by the kick pattern of a specific track.

Read post
Build LogDevOps
#99
2026-06-245 min read

Auto-mode opened the PR. It didn't merge it. That was gap one.

Phase 9's 'self-driving overnight' was overstated by two wiring gaps. A 09:00 BST live run on 11 June found both. The afternoon of fixes taught more about auto-mode's real edges than any pre-flight design session.

Read post
bb financeiOS
#100
2026-06-245 min read

I had the Accounts calendar scoped as one level. Mid-design I deepened it to three.

Phase K shipped a horizontally-scrollable daily-activity strip on the Accounts screen. Phase O was meant to replace it with a calendar — I had a compact, single-level surface already scoped. Mid-design I deepened the ask to full-screen plus day mode, and a back-nav regression in round-2 device QA explains why that was the right call.

Read post
DVLAWPipeline
#101
2026-06-246 min read

Phase B was hitting 20% autonomous success. The slot had never existed in the schema.

Five queue rows tried and rejected in three seconds. Three days of SLA fixes, substitute logic, and alarms, all patching around the same absence. The 20% pipeline success rate wasn't a scheduling problem — there was no schema entity for the thing being scheduled.

Read post
Build LogiOS
#102
2026-06-246 min read

The Accounts screen took four iterations. Each one bought fidelity by spending scope.

Sprint 2 shipped a SwiftUI list with CRUD. Phase K rebuilt it into a module stack with a trend chart and activity strip. Phase O turned the strip into a three-level calendar flow. Round-2 device QA on AnF found the back-nav bug that came with it.

Read post
SEOBuild Log
#103
2026-06-236 min read

Eight cannibalisation pairs, one prefix strip, one PR

A numeric prefix in every calculator slug had created eight cannibalisation pairs — Google couldn't determine which URL was authoritative, so neither ranked with confidence. The fix required one atomic operation across content, routing, and the internal link graph: universal prefix strip, 23 permanent redirects, every MDX cross-link repointed. Not three PRs. One.

Read post
Build LogiOS
#104
2026-06-235 min read

The 4-bit LLM hallucinated my Halifax statement. A band-based parser fixed it.

bb finance's Phase H spike wired a 4-bit quantised Llama 3.2 1B as the primary PDF extraction route. On real Halifax statements it hallucinated at a destructive rate — page 3 has 34 transactions; the model returned something else. PF-002 disabled the LLM path and replaced it with a deterministic band-based parser that lands 54 of 54.

Read post
Build LogDVLAW
#105
2026-06-235 min read

The publishing queue ran at 20% success rate. Fixing it took three changes that only work together.

Four autonomous publishing slots expired before the pattern became clear. Sibling cancellation, slot fallback, and a missed-slot alarm are a set — without all three, the queue degrades silently.

Read post
Build LogDVLAW
#106
2026-06-225 min read

20% in 72 hours: rewriting the slot scheduler's SLA recovery

Twenty percent autonomous success across five scheduled slots in 72 hours. The substitute pool was running but consuming the wrong inventory — draining future windows to cover present failures. Three mechanisms and a first-class slot state machine fixed it.

Read post
iOSSwift
#107
2026-06-225 min read

Four quest types. None of them read your transactions.

An iOS budget app shipped a gamification layer backed by a hardcoded mock array. Phase C replaced it with QuestGenerator — a pure function that derives up to four quests per day from real transaction history. What changed wasn’t the number of quests. It was whether the quests knew anything about the user.

Read post
Build LogDevOps
#108
2026-06-225 min read

I treated publication slots as timer events. Three days of SLA breaches say otherwise.

Between 11 and 13 June, the 09:00 BST publication slot fired and produced nothing three times in a row. Each incident had a different surface cause. All of them trace back to the same modelling mistake.

Read post
Build LogAI Tools
#109
2026-06-225 min read

The pipeline was wrong before the model ever ran

PR #53 was the first article the X.8 editorial pipeline shipped since H-1/H-2/H-3 lifted, unblocked by a single bug fix in ground.py. Not a prompt change. Not a model upgrade. A function called calculator_scores had a bug, and the model had been synthesising from whatever it returned.

Read post
iOSSwift
#110
2026-06-216 min read

accessibilityReduceMotion should be a contract. Phase D made it one.

Phase D of an iOS budget app Cursed Energy feature adds five animated layers across sigil, energy, claim, level-up, and streak milestone surfaces. Every one checks accessibilityReduceMotion before firing — a hard gate, not a hint. The uniformity was a rule established on the first addition and held through to the fifth.

Read post
Build LogDVLAW
#111
2026-06-215 min read

Four expired slots and the SLA recovery rule we learned in sequence

Between 12 and 14 June, four scheduled DVLAW slots expired without autonomous recovery. Each failure confirmed the same thing: sibling cancel, substitute fallback, and a missed-slot alarm don't work in isolation. They're one system.

Read post
iOSSwiftUI
#112
2026-06-215 min read

The Accounts calendar strip passed every preview check. On my test iPhone, it answered the wrong question.

The Phase K Accounts screen shipped with a horizontally-scrollable calendar strip. Device QA on my test iPhone showed it was answering the wrong question, so mid-design I deepened Phase O to a three-level navigation flow: inline calendar, full-screen month view, day mode. SwiftUI preview had nothing to say about any of it — the back-nav regression that followed only surfaced under a real thumb.

Read post
DVLAWBuild Log
#113
2026-06-215 min read

The sibling-rehash rule: wired in the prompt, enforced in the filter

The picker generates three thesis variants per upgrade decision. Multiple upgrade taps on the same topic, same source material, different angles: the pipeline could queue two articles that were really one. Fixing that took two layers — one in the drafter prompt, one in the substitute filter — because prompts are probabilistic and filters are not.

Read post
Build LogEditorial
#114
2026-06-206 min read

25 PRs, a rescued BoE fetcher, and a composer taught restraint: the editorial pipeline ships

PR #53 merged on 12 June: the first article through the full X.8 grounded editorial pipeline. The morning sweep showed three gaps that had been quietly open — a stale PR that would have deleted the BoE rates fetcher, a composer inferring beyond its sources, and a design sprint that completed the day after. All three closed within 72 hours.

Read post
Build LogiOS
#115
2026-06-206 min read

Five sprints inside one PR: what an iOS budget app's side-branch pattern reveals about tracking

PR #10 on an iOS budget app landed five complete features in a single merge. Each devlog entry reads as a self-contained sprint brief with its own type, its own boundary, its own completion signal. PR-level granularity and feature-level granularity are not the same number.

Read post
Build LogiOS
#116
2026-06-205 min read

The dedup layer had three hash schemes. CDImportSource replaced them — and four banks validated with zero per-bank code.

The an iOS budget app import layer had three coexisting hash schemes with no shared contract between them. Collapsing them into CDImportSource — a unified source-attribution model — was the structural prerequisite for universal CSV and PDF parsers that validated across Monzo, Halifax, Revolut, and HSBC.

Read post
Build LogAI Tools
#117
2026-06-205 min read

The S-4 cohort made two editorial pipeline decisions. I shipped them.

Two weeks of UK Calculators editorial pipeline sprints ended with two decisions that came from the cohort data, not preference: live Bank of England rate fetches and a constrained LLM composer. The pipeline silently stalled for four days after shipping.

Read post
iOSSwift
#118
2026-06-196 min read

Cursed Energy Phase C: wiring an iOS budget app's quest system to real transaction history

The an iOS budget app gamification layer had quest cards, a claim button, and a streak counter. None of it read from actual spending. Replacing a hardcoded array with a transaction-aware QuestGenerator turned decorative chrome into a feedback loop that surfaces real patterns.

Read post
Build LogiOS
#119
2026-06-195 min read

Device QA found three regressions. The simulator had approved them all.

Round-2 device QA on bb finance flagged a navigation stack popping two levels instead of one, ProMotion locked at 60Hz on a 120Hz panel, and category rules over-reaching on shared word fragments. None of them showed in the simulator.

Read post
SEOBuild Log
#120
2026-06-195 min read

Eight calculators were cannibalising each other. One prefix strip fixed it in 72 hours.

A site-wide SEO audit against ukcalculator.uk surfaced 8 routes competing with themselves for the same search intent. The fix — strip the NN- prefix, issue 308 redirects across 23 routes, repoint every internal cross-link — had to land as a single atomic operation or it would introduce crawl noise between deployments. Three days later, Google had started indexing.

Read post
Build LogDVLAW
#121
2026-06-196 min read

Five slots, twenty percent: the substitute pool had no editorial policy

Five scheduled publishing slots, four expirations, and a breach chain that exhausted six candidates in three seconds. The scheduler fired on time every run. The substitute pool was offering articles the drafter’s citation rules were going to refuse.

Read post
Build LogiOS
#122
2026-06-195 min read

GOOGLE plus CLOUD matched SoundCloud. Why the fuzzy categoriser had to go.

Phase Q's fuzzy categoriser propagated category matches silently. Device QA on Phase R's part-based builder immediately surfaced an ANY-match failure: GOOGLE plus CLOUD matched SoundCloud. Version two adds exclusions and per-row overrides; the difference is that the user can now see what the matcher is doing.

Read post
SEOBuild Log
#123
2026-06-195 min read

Google ranks URLs, not intentions: the NN- prefix strip that resolved eight cannibalisation pairs on ukcalculator.uk

A site-wide SEO audit of ukcalculator.uk surfaced eight cannibalisation pairs before a single meta-tag was touched. The common thread: a numeric sort prefix on every affected slug, one that had never been intended as a ranking signal. Fixing the URLs outweighed everything else in Phase 1.

Read post
Build LogiOS
#124
2026-06-185 min read

Five features, one PR: how an iOS budget app ships concurrent phase work without a merge queue

On 2026-06-14, five feat entries landed in an iOS budget app across Phases C, D, and E — all tagged 'same PR #10.' Treating commits as the concurrency primitive instead of branches let three phases advance in parallel without a merge queue or conflict chain.

Read post
iOSSwiftUI
#125
2026-06-186 min read

I could have built this twice. ModuleOrderStore is why I didn't.

Making Home and Accounts modules user-rearrangeable could have meant two separate order stores, one per screen. ModuleOrderStore — a @MainActor singleton mirroring an existing PaletteStore pattern — is the reason it's one. The device QA round on AnF confirmed the ordering engine held; six other issues confirmed the QA was necessary.

Read post
Build LogiOS
#126
2026-06-186 min read

One parser for Monzo, Halifax, Revolut and HSBC: how heuristic matching beat four bespoke importers

The on-device LLM for PDF extraction hallucinated on a real Halifax statement. That failure produced a band-based parser that hits 54/54 transactions. The same heuristic approach on the CSV side means one importer, four banks, zero per-bank code paths.

Read post
Build LogiOS
#127
2026-06-185 min read

SoundCloud showed up under my Google Cloud rule on device. That's when part-based matching replaced the algorithm.

Phase Q shipped smart category propagation powered by a fuzzy matcher. Device QA of the Phase R match builder found the structural over-reach immediately: ANY-match on GOOGLE and CLOUD pulled SoundCloud in via 'cloud' and two Google One rows in via 'google'. Phase R v2 added exclude words and per-row select-all to close the gap — because a rule you can read is a rule you can fix.

Read post
Build LogiOS
#128
2026-06-175 min read

An iOS budget app: five rounds of device QA found the same defect every time

Three of the Home screen's gamification blocks were non-interactive labels. The Streak block's Check In button opened the transaction form. Five device-QA sweeps — Phases L through Q — kept finding the same thing: the interface was describing things users expected to control.

Read post
iOSSwift
#129
2026-06-156 min read

Five features, one PR: the two shared-state promotions that had to come first

PR #10 for an iOS budget app bundled a palette picker, a motion layer, a streak milestone overlay, a category-budget quest, and a save-target preference into a single side branch. Getting them to co-exist required promoting BBPalette.current and UserProfileStore before the features could be wired.

Read post
Build LogDevOps
#130
2026-06-145 min read

Two correct cancellations, two SLA breaches, four manual ships

On 13 June, the 09:00 and 12:00 BST editorial slots both failed in the same day. G-L3 cancelled the queued articles correctly each time. Manual recovery covered every slot. The experience made the gap between row-level correctness and slot-level reliability impossible to ignore.

Read post
Build LogDevOps
#131
2026-06-135 min read

Four sprints shipped before the installer resolved to the right directory

The idea park soak cron installer used a directory convention copied from the article pipeline, correct in the article pipeline's layout and wrong in the idea park-soak's co-located layout. Two more post-merge fixes followed the same shape: a sanitiser wired into one code path but not the other, and a caller convention documented but never enforced.

Read post
Build LogLLM Engineering
#132
2026-06-135 min read

Retries must be stateless, or the loop learns to cheat

The first live probe of the calibration gate against the BoE MMC article produced a 9,340-character draft that blocked correctly. Getting to a pass from there without teaching the loop to game its own gate took two days of doctrine.

Read post
Build LogEditorial Pipeline
#133
2026-06-136 min read

The prompt that made Haiku hallucinate, every single time

Every iteration of the UK Calculators redraft loop produced the same failure: Haiku returning plausible-sounding figures with no real source. The fix wasn't better prompting. It was removing the question entirely.

Read post
Build LogNewsletter
#134
2026-06-135 min read

Three newsletter hotfixes. The events table found all of them.

The newsletter form went live on 9 June. I subscribed from my own address and got nothing. No row, no email, no error. Three consecutive bugs followed, all found the same way: reading the events log, not the code.

Read post
Build LogDevOps
#135
2026-06-125 min read

No Composer, no autoloader: the newsletter backend cPanel rewarded

The deployment target was a cPanel shared host with FTP access. Composer wants SSH or a committed vendor directory. Neither fits cleanly on shared hosting. The alternative was require_once, six PHP classes, and a 190-line schema that doubles as documentation. Six sprints in, the backend is completely understood.

Read post
Build LogAgentic AI
#136
2026-06-126 min read

One osascript harness, two consumers — how skipping Archon kept the article pipeline stack composable

After the variant-picker shipped, the next call was architectural. Route thesis generation through Archon, or build a project-owned harness and own the primitive. The harness won. What emerged was a two-consumer pattern — thesis generation and voice rewriting off the same base — that Archon would have made awkward.

Read post
Build LogDevOps
#137
2026-06-125 min read

Scheduling articles through Telegram taught me that cron is the wrong model

The article pipeline pipeline could draft and voice-fix articles but had no scheduling layer. Adding one took six sprints, not because the cron was hard but because scheduling through Telegram needs to capture intent, not timestamps. The grammar parser, the 2×2 keyboard, and the 48-hour grace policy are the same design decision expressed three different ways.

Read post
Build LogAI Tools
#138
2026-06-126 min read

Three articles cleared every gate. None of them cleared the style guide.

Phase 9 of the article pipeline auto-pipeline shipped on 2026-06-11. Within 24 hours I was manually patching three articles that had cleared every automated check but violated the style guide's em-dash budget on all three. The scrubber had the right rule. It was checking the wrong scope.

Read post
Build LogBBBrain
#139
2026-06-115 min read

Every post-merge the idea park fix was the same fix

Provenance sanitisation, SCRIPT_DIR co-location, BB_CALLER lint — three fixes shipped after the idea park merged. They look like different problems. They’re not. All three are the audit trail recording what it could infer rather than what actually happened.

Read post
Build LogAI Tools
#140
2026-06-115 min read

Stop retrying the prompt: what the brief ledger taught the image harness

Four sessions into generating hero illustrations, I was still fixing the same structural mistakes on different posts. Each bad render was a lesson. The retry loop wasn't keeping them.

Read post
Build LogVoice Design
#141
2026-06-105 min read

Both voice iterations failed the Cash ISA test. I shipped the original.

Two iterations of the uk-calculator-voice skill (analytical v2.0.0 and warmth-corrected v2.1.0) both failed the same blind A/B on Cash ISA drafts. The original v1.0.0 won both rounds. The ship was v1.1.0: a reset to the passing baseline with the recovery path formalised, not a third iteration attempt.

Read post
Build LogBBBrain
#142
2026-06-105 min read

The inbox filter model drops strangers silently. I built a queue instead.

Inbox filters drop what they don't recognise. I wanted a record instead: every unknown sender parked, every blocked arrival logged, nothing silently gone. Five tables, four sync branches, and a historyId cursor later, the editorial pipeline's Inbox Hub does exactly that.

Read post
Build LogAgentic AI
#143
2026-06-096 min read

Archon was burning quota. The fix was a hook, not a scheduler.

Three Archon runs in flight simultaneously, two of them fired without a deliberate decision. The instinct was to build a smarter scheduler. What worked was a global PreToolUse hook that intercepts archon workflow run and forces a pause before anything spawns.

Read post
Build LogInbox
#144
2026-06-085 min read

Making Gmail tractable in a day. Four branches and one partial index.

The Inbox Hub shipped in five sprints, all on the same day. The classifier is four comparisons against a rules table. The speed comes from a partial index on pending senders, not from the sync logic. Neither changed how I read email.

Read post
Build LogBBBrain
#145
2026-06-075 min read

Sender reputation first: why the Inbox Hub has no messages table

Building an inbox triage surface meant deciding what goes in the primary lookup table. The answer wasn't messages — it was senders. Five SQLite tables, a partial index on pending unknowns, and a 60-second badge later, the schema design is the product.

Read post
Build LogDevOps
#146
2026-06-066 min read

I built six sprints of article scheduling. For four of them, nothing fired.

Four sprints of Telegram button wiring, queue state machines, and free-text time parsing — all recording intent into `article_queue` without dispatching a single article. Sprint 5 was the first one that actually fired. Separating mechanism-to-record from mechanism-to-execute isn't a new idea; applying it deliberately at the sprint level is.

Read post
Build LogDVLAW
#147
2026-06-055 min read

The schedule queue took four sprints to remember. One to act.

After four sprints of B-schedule, a scheduled article existed as a database row with a correct timestamp. No article had published. Sprint 5 added the sweep daemon and publisher_lock. That is when scheduling became real.

Read post
Build LogDVLAW
#148
2026-06-045 min read

A missed slot at 09:00 should not silently vanish: building past-due grace into the article pipeline publisher

The `schedule_sweep` runs on a laptop. Laptops sleep. Without a grace policy, an article scheduled for 09:00 silently strands when the machine wakes at 09:07. Sprint 6 of B-schedule — past-due grace plus 48-hour hard-expire — turns that silent drop into a recoverable state with a reason, an audit trail, and a path back to publish.

Read post
Build LogPython
#149
2026-05-318 min read

The classifier is the product: how four branches replaced an inbox

Inbox Hub is five SQLite tables, twelve route handlers, four Shadow DOM components, and a launchd cron. Strip those away and what remains is a four-branch decision tree that runs on every message. Everything else is plumbing around that core.

Read post
Build LogPython
#150
2026-05-306 min read

monkeypatch lies to you when your tests run in subprocesses

The fixture looked correct. The patch was applied. The subprocess ignored all of it and wrote to the real registry. Three days of roadmap work taught me that monkeypatch only rebinds the parent process — env-var overrides are the only isolation that survives a fork.

Read post
Build LogBBBrain
#151
2026-05-307 min read

One input to rule the dashboard: how the editorial pipeline's chat surface replaced three UIs

The editorial pipeline's chat interface started as a conversational wrapper. Two days of commits later it had absorbed the Archon SPA, the dashboard nav, and a 16-command palette. The unifying mechanism is simpler than it looks.

Read post
Build LogAI Tools
#152
2026-05-287 min read

Ten AI-prose tells, one shell script, no more guessing

The em-dash density in my own published articles was running at four times the normal rate for edited prose. That was a measurable problem. So I made it measurable: codified ten AI-prose tells into STYLE-GUIDE.md and a pre-publish shell audit that catches them mechanically.

Read post
SecurityBuild Log
#153
2026-05-287 min read

The backtick that could run anything: hardening AppleScript shell escaping

A Sprint 2.11 review flagged a shell command-substitution gap in a single Python helper. Backticks and dollar signs were passing through unescaped into a double-quoted `do script` string, meaning a crafted issue title could execute arbitrary code. The fix was four lines. Understanding why it mattered took longer.

Read post
Build LogDevOps
#154
2026-05-286 min read

Two assumptions the pipeline held until it shipped

B8b's first end-to-end Telegram ship-tap exposed two bugs that had been invisible in every prior test. Neither was logic. Both were assumptions the pipeline had been making silently since the day the code was written.

Read post
Build LogDevOps
#155
2026-05-286 min read

Telegram 409 Conflict: two bots, one token, infinite errors — why a bot registry is infrastructure

Retrofitting the editorial pipeline's Telegram modules revealed that the tunnel bot and the brain server had been polling the same token for weeks, throwing 409 conflicts that neither log named clearly. The fix wasn't a config tweak. It was accepting that one-bot-per-purpose needs to be enforced at registration time, not discovered at incident time.

Read post
Build LogAgentic AI
#156
2026-05-286 min read

Why the editorial pipeline's rewrite layer runs on a project-owned harness, not Archon

The Opus rewrite layer inside the editorial pipeline's de-AI-ish stack runs through a project-owned osascript Terminal harness, not a general orchestration framework. That choice was deliberate and narrow. Here's what it cost and what it bought.

Read post
AccessibilityBuild Log
#157
2026-05-227 min read

Audits find what's wrong, not what's missing

A page-by-page audit ran for three days catching deprecated ARIA roles, fabricated copy, and missing hover-pause behaviour. Then I opened the site on my phone and the nav menu wasn't there. Not wrong. Just not there. That's a class of bug audits can't catch, and the fix isn't to audit harder.

Read post
Build LogDevOps
#158
2026-05-215 min read

macOS won't let your cron read your work: three days inside TCC

A daily launchd job that reads from /Volumes/b/ looked trivial. Three days, four wrong approaches, and one AppleScript .app bundle later, I'd learned why granting Full Disk Access to a shell script is a UI fiction.

Read post
ArchitectureMDX
#159
2026-05-217 min read

An MDX content pipeline grows three kinds of complexity

Naïve MDX setups (one file in, one HTML out) hit three walls as they scale. Routing complexity. Authoring complexity. Citation complexity. Each grows non-linearly with post count; each has a single high-leverage fix.

Read post
AI ToolsBuild Log
#160
2026-05-218 min read

I built this with Claude Code. The bugs weren't where I expected.

Three days into a page-by-page audit of my own site, I realised the bugs Claude Code had left behind weren't logic errors. They were hypotheses it had inferred from context, presented as facts. The reflex I needed wasn't suspicion. It was verification.

Read post
Web DevDevOps
#161
2025-04-181 min read

Static Next.js on cPanel in 2025

GitHub Actions to FTP to cPanel. Simpler than it sounds, with a few real gotchas worth documenting.

Read post