<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Robert Floyd Dugger</title>
    <description>The latest articles on DEV Community by Robert Floyd Dugger (@robert_floyddugger_6f9a4).</description>
    <link>https://dev.to/robert_floyddugger_6f9a4</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2466169%2Ff64dc048-fa8a-4a64-87b4-07b20cd85545.png</url>
      <title>DEV Community: Robert Floyd Dugger</title>
      <link>https://dev.to/robert_floyddugger_6f9a4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/robert_floyddugger_6f9a4"/>
    <language>en</language>
    <item>
      <title>A $120 Bill for a Service That Runs Sixty Seconds a Day</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Sun, 12 Jul 2026 19:33:54 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/a-120-bill-for-a-service-that-runs-sixty-seconds-a-day-2103</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/a-120-bill-for-a-service-that-runs-sixty-seconds-a-day-2103</guid>
      <description>&lt;p&gt;A service I run — a Slack-triggered compliance job that fans out to a few APIs in parallel and finishes in a few seconds — turned in a Cloud Run bill over $120 for the month. It gets invoked 1-5 times a day. I did the math on that before digging further: even at five seconds of real work per call, five calls a day, that's under a minute of actual compute across the whole month. A hundred and twenty dollars for a minute of work is the kind of number that makes you stop and check your assumptions.&lt;/p&gt;

&lt;p&gt;It wasn't Firestore. It wasn't logging. It wasn't the Slack API calls. Over 80% of the bill was Cloud Run itself.&lt;/p&gt;

&lt;h2&gt;The Setting I'd Forgotten About&lt;/h2&gt;

&lt;p&gt;Cloud Run has two modes, and I'd set mine to the expensive one without really registering that I'd done it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gcloud run services describe SERVICE_NAME --format="value(spec.template.spec.containerConcurrency, spec.template.metadata.annotations)"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;min-instances&lt;/code&gt; was set above zero. I'd done it months earlier to kill cold-start latency — nobody likes waiting a few extra seconds for the first request of the day. What I hadn't fully priced in: setting it above zero means Cloud Run keeps a container alive around the clock, billed by the hour, whether a request ever shows up or not. Mine was idling roughly 1,440 minutes a day to cover a job that needed maybe one.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gcloud run services update SERVICE_NAME --min-instances=0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One flag. That's the whole fix.&lt;/p&gt;

&lt;h2&gt;The Part That Actually Bugged Me&lt;/h2&gt;

&lt;p&gt;The service had been running for over a year without a single missed job. That's exactly why I never looked at the bill closely — it worked, so I never had a reason to open the billing console and ask why. A service that fails gets investigated. A service that quietly does its job every day for a year doesn't. The failure mode here wasn't the code. It was that reliability made the waste invisible.&lt;/p&gt;

&lt;p&gt;That's the actual lesson, more than the specific flag: cost problems hide best in the things that work. If something's been running clean for months, that's not evidence there's nothing to check — it might just mean nobody's had a reason to check.&lt;/p&gt;

&lt;h2&gt;Cold Starts, Revisited&lt;/h2&gt;

&lt;p&gt;The reason I'd set &lt;code&gt;min-instances&lt;/code&gt; above zero in the first place — cold-start latency — turned out to matter a lot less than I'd assumed for this use case. The service is triggered by a human submitting a Slack command and waiting for a reply. A few seconds of occasional added latency on a request that's already interactive and infrequent is a real trade, but it's a small one against paying for a warm container 24/7 to save it.&lt;/p&gt;

&lt;p&gt;Scale-to-zero is the right default for anything shaped like this: infrequent, bursty, tolerant of a few seconds' wait. If a service's real invocation pattern looks more like a handful of calls a day than a steady stream, &lt;code&gt;min-instances=0&lt;/code&gt; is very likely underpriced right now and worth a five-minute check.&lt;/p&gt;

&lt;h2&gt;Related&lt;/h2&gt;

&lt;p&gt;I wrote up the business side of this same finding separately — what a missed DNC scrub actually costs versus what the tooling to prevent it costs, with real TCPA numbers: &lt;a href="https://blog.rfditservices.com/2026/07/12/how-much-should-dnc-compliance-automation-cost-to-run/" rel="noopener noreferrer"&gt;How Much Should DNC Compliance Automation Cost to Run?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More on the compliance system itself — the Slack interface, the fan-out architecture, the test floor — is on the &lt;a href="https://rfditservices.com/projects/dnc-compliance-tool/" rel="noopener noreferrer"&gt;project page&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>python</category>
      <category>gcp</category>
      <category>cloudrun</category>
    </item>
    <item>
      <title>I Didn't Plan a Curriculum. I Just Kept Solving Problems.</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Wed, 01 Jul 2026 23:06:25 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/i-didnt-plan-a-curriculum-i-just-kept-solving-problems-18lg</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/i-didnt-plan-a-curriculum-i-just-kept-solving-problems-18lg</guid>
      <description>&lt;p&gt;In spring 2023 I had a spontaneous lung collapse. I spent a week in a hospital bed with a tube in my chest and about two months recovering afterward. At some point during the recovery I opened Coursera and started the Google IT Support certificate. Not because I had a plan. Because I finally had time to sit still and I needed something to work toward.&lt;/p&gt;

&lt;p&gt;That's the actual origin of what became a three-year credential arc. Not ambition. A collapsed lung and nowhere to be.&lt;/p&gt;




&lt;p&gt;Before that, the resume looks like what it is: someone trying to figure it out. DoorDash with a newborn, my partner and I trading off driving and childcare because that was how we covered both. Pizza delivery before that. Dishwashing. A call center in Riviera Beach where I went from fronter to salesman to managing the junior closer department in about three months, which told me something about how I learn — fast, from inside a problem, by doing it wrong first.&lt;/p&gt;

&lt;p&gt;That call center background matters more than it looks. I understand contact center floors from the inside. I know what the manual work actually costs, what breaks first, what nobody has time to fix. When I eventually built automation tools for a dialer operation, I wasn't guessing at the problem. I'd been the person doing the manual version of it.&lt;/p&gt;




&lt;p&gt;I finished the Google IT Support cert in January 2024 — five courses, started June 2023, spread across my recovery and the months after. By then I was already in a data and IT role, already writing Python, already shipping things that worked. The cert came after the skill. That pattern repeated.&lt;/p&gt;

&lt;p&gt;Google Data Analytics: September 2024 through July 2025. Ten months. While I was building an ETL pipeline that processed 700,000 records in under 8 minutes using pandas vectorization. The cert named what I was already doing.&lt;/p&gt;

&lt;p&gt;Google Prompting Essentials: finished February 2026. I'd been using Claude as a design partner for months by then — Director, Pipeline, Agent — a full methodology for AI-assisted development. The cert told me I was doing prompt engineering. Sure.&lt;/p&gt;

&lt;p&gt;Google AI Professional: finished today, July 1, 2026. Seven courses. The last three — Writing and Communicating, Content Creation, App Building — I finished this afternoon while waiting for a Cloud Run deployment. I have a 24-tool MCP server that manages my entire YouTube channel from conversation. I have a blog pipeline that publishes to WordPress and Dev.to simultaneously. I have an inbox triage system that classifies 5,000 emails using few-shot learning. Every module felt like reviewing something I'd already built.&lt;/p&gt;




&lt;p&gt;Here's what I've learned about how I actually learn: I don't take a course and then apply it. I hit a problem I can't solve, I solve it badly, I solve it less badly, and then at some point I find the credential that puts a name on what I figured out. The cert is not the education. The cert is the signal to other people that the education happened.&lt;/p&gt;

&lt;p&gt;That's not a shortcut. It's slower than doing it the right way. There's no professor to tell you when you're wrong, no structure to catch the gaps, no cohort to compare yourself against. You find out you were wrong when the thing breaks in production at 11 PM and you have to figure out why.&lt;/p&gt;

&lt;p&gt;But it's the path that was available. No bootcamp, no degree, no runway to spend six months learning before building anything. A GED, a collapsed lung, a newborn, and a lot of late nights.&lt;/p&gt;




&lt;p&gt;I'm halfway through Google IT Automation with Python — Course 4 of 7, Module 3, debugging section. It's the most technically grounded cert in the stack and the one I need the least. I've been writing Python automation in production for two years. I'll finish it anyway because the credential matters for what comes next, and because finishing things is a habit worth keeping.&lt;/p&gt;

&lt;p&gt;UX Design is queued after that. Google offers a full 8-course certificate — wireframing, prototyping, usability testing, Figma end to end, three portfolio projects. Because I keep hitting the same wall: I know what I want the screen to do and I'm slow to decide how to lay it out. That's a gap. I'll close it.&lt;/p&gt;

&lt;p&gt;The direction is becoming clearer in hindsight. IT infrastructure, data, automation, AI, now design. I didn't plan that arc. It's just what the problems kept requiring.&lt;/p&gt;




&lt;p&gt;Google IT Support (January 2024) · Google Data Analytics (July 2025) · Google Prompting Essentials (February 2026) · Google AI Professional (July 1, 2026) · Google IT Automation with Python (in progress)&lt;/p&gt;

&lt;p&gt;rfditservices.com&lt;/p&gt;

</description>
      <category>career</category>
      <category>python</category>
      <category>sdd</category>
      <category>ai</category>
    </item>
    <item>
      <title>Eight Shorts, Same Timeslot. The Engine Found Them.</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Tue, 30 Jun 2026 23:50:28 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/eight-shorts-same-timeslot-the-engine-found-them-2813</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/eight-shorts-same-timeslot-the-engine-found-them-2813</guid>
      <description>&lt;p&gt;At 11:40 PM I asked my AI what was on my YouTube calendar for August.&lt;/p&gt;

&lt;p&gt;It told me I had eight videos scheduled to publish at the exact same timestamp on the same dates. Two Shorts, one slot. Eight times over.&lt;/p&gt;

&lt;p&gt;It also told me the fix, proposed the moves, and waited for my confirmation before touching anything.&lt;/p&gt;

&lt;p&gt;I didn't open YouTube Studio once.&lt;/p&gt;




&lt;p&gt;That's the short version of what RFD_YT_Engine is. The longer version starts about two months earlier, when I was running a pipeline called ContentEngine that was supposed to generate YouTube Shorts from AI-written game reviews. It had nine stages, a script generator, a brief generator, a voice synthesis layer, and a Pollinations.ai fallback for when nothing else produced a usable image. It was elaborate.&lt;/p&gt;

&lt;p&gt;It also produced videos nobody watched, including me.&lt;/p&gt;

&lt;p&gt;The pivot was simple: stop scripting. Use real gameplay footage. Film what actually happens when you play a game for the first time, cut out the moment that made you react, and put it online. No narration. No brief. No AI-written hook. Just the moment.&lt;/p&gt;

&lt;p&gt;The pipeline that came with ContentEngine didn't fit that model. So I built a new one from scratch.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What RFD_YT_Engine actually is&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An 8-domain Python system that manages the full lifecycle of a YouTube channel — from raw session recording through to published video — with a 24-tool MCP server that exposes the entire thing to Claude Desktop.&lt;/p&gt;

&lt;p&gt;The eight domains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capture&lt;/strong&gt; — OBS integration, session monitoring, game detection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ingest&lt;/strong&gt; — Whisper transcription, beat extraction, session tagging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production&lt;/strong&gt; — Shorts assembly via FFmpeg, Highlights assembly with bridge TTS, beat-to-clip mapping&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribution&lt;/strong&gt; — YouTube Data API v3 uploads, metadata resolution, scheduled publishing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catalog&lt;/strong&gt; — Full channel mirror in local SQLite, 167 videos with all 11 detail columns hydrated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduling&lt;/strong&gt; — Calendar management, collision detection, round-robin reweave&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming&lt;/strong&gt; — OBS WebSocket control, stream session management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface&lt;/strong&gt; — The MCP server. The only domain allowed to call across domain boundaries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture rule that held through every phase: one-directional dependency. No domain imports another's modules. Everything flows through shared infrastructure or the Interface layer. Eleven phases of development, zero ADR violations.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The YouTube API surface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built the full YouTube Data API v3 and Analytics API v2 surface from scratch because the existing libraries were either too thin or too opinionated about what you could do with them.&lt;/p&gt;

&lt;p&gt;What that means concretely:&lt;/p&gt;

&lt;p&gt;The first sync attempt using search().list() returned 64 videos. The correct number was 167. The difference: search only returns public videos. Private, scheduled, and unlisted are invisible to it. Switching to the uploads playlist fixed it. 167 videos, all detail columns hydrated, in 4 API calls.&lt;/p&gt;

&lt;p&gt;update_video_metadata() had a silent data corruption bug. YouTube replaces the entire snippet object on update. Sending only the fields you want to change wipes the rest — tags gone, category reset. The fix: fetch the current snippet first, merge the changes, send the complete object.&lt;/p&gt;

&lt;p&gt;Traffic sources and audience retention are now queryable from conversation. How viewers found each video. Where they stopped watching. Direct tool calls, no dashboard.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Collision detection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The channel has 89 videos scheduled for future publication. The same-timestamp conflicts weren't obvious in YouTube Studio — it shows dates, not exact times, and two videos at 2026-08-29T02:00:00Z look identical until one of them fails to publish.&lt;/p&gt;

&lt;p&gt;Two detection functions:&lt;/p&gt;

&lt;p&gt;detect_collisions() finds same-game streaks exceeding a threshold across consecutive days. The Hotline Miami run that stretched six days without interruption — that's the target. The fix was interweaving 8 displaced Shorts into the streak window while filling the empty September calendar.&lt;/p&gt;

&lt;p&gt;detect_same_day_collisions() classifies each date with multiple videos as either true_conflict (same exact timestamp, real problem) or multi_slot (different times, intentional). A Short at 2AM and a long-form session at 10PM on the same Sunday is the correct pattern. Two Shorts both at 2AM is a conflict. The function names the videos in both directions, and flags the content type — short, highlights, or long_form — derived from duration and title signal.&lt;/p&gt;

&lt;p&gt;The eight true conflicts were resolved with one apply_batch_reschedule call after reviewing the preview. Ten video dates changed. No YouTube Studio.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What it took&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;190+ certified tests. Phase-gated development with verified floors — no phase starts until the previous one passes at exactly the stated count. Every architectural decision locked in an ADR. The Director → Pipeline → Agent methodology throughout: I wrote the directives, the agent implemented, I verified against raw pytest output. No agent summary counts as proof.&lt;/p&gt;

&lt;p&gt;The most expensive bugs were the ones that looked like success. 64 videos that were actually 167. A metadata update that silently wiped tags. A calendar that showed empty because scheduled_at was never being written even though the API returned the data. Each one found by querying what the system actually knew versus what it should have known.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The outcome&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;167 videos in a local SQLite database. All detail columns hydrated. All scheduled dates correct. Collision detection live. Calendar management, metadata updates, batch reschedules — from conversation.&lt;/p&gt;

&lt;p&gt;The infrastructure layer for a channel that produces 1–2 Shorts per day and a long-form session every Sunday. Everything above the infrastructure — recording, playing, picking the moment — is still manual. That's the part that should be.&lt;/p&gt;




&lt;p&gt;Stack: Python · SQLite · YouTube Data API v3 · YouTube Analytics API v2 · FFmpeg · OBS WebSocket · MCP&lt;/p&gt;

&lt;p&gt;Methodology: Spec-Driven Development · Director → Pipeline → Agent · phase-gated test floors · ADR-documented decisions&lt;/p&gt;

</description>
      <category>youtube</category>
      <category>python</category>
      <category>mcp</category>
      <category>sdd</category>
    </item>
    <item>
      <title>How to Forecast End-of-Day Call Center Performance</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Mon, 29 Jun 2026 21:19:40 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/how-to-forecast-end-of-day-call-center-performance-4ac9</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/how-to-forecast-end-of-day-call-center-performance-4ac9</guid>
      <description>&lt;p&gt;By mid-afternoon, you can know where your floor will close by end of day — accurately enough to make the remaining hours a decision, not a guess. Here's how intraday performance forecasting works and what it takes to build it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With Yesterday's Numbers
&lt;/h2&gt;

&lt;p&gt;Most contact centers have end-of-day metrics. Dials, connects, conversion rate against target. Those numbers are accurate, useful for trend analysis, and arrive the next morning.&lt;/p&gt;

&lt;p&gt;By the time you see them, the day is already over.&lt;/p&gt;

&lt;p&gt;The decisions that drive outcomes happen during the day — in real time, when hours remain to influence the result. Do you push harder in the final stretch? Adjust campaign priority? Pull a server that's underperforming? Those decisions get made in the afternoon with one question underneath all of them: where are we going to close?&lt;/p&gt;

&lt;p&gt;If you're answering that question with yesterday's data and experienced intuition, you're working with an information deficit that compounds every day it stays open.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Intraday Forecasting Works
&lt;/h2&gt;

&lt;p&gt;The system records dial conversion rates at regular intervals throughout the business day. Not a snapshot at end of day. A continuous read of how the floor is performing as it performs.&lt;/p&gt;

&lt;p&gt;Every morning, before the floor opens, the model retrains. It processes the intraday conversion patterns from previous days — how conversion tends to develop through the morning, when it typically accelerates, when it softens, how afternoon performance differs from morning — and calibrates to the current operation's historical data.&lt;/p&gt;

&lt;p&gt;As the day runs, the forecast updates on a regular schedule. Each update incorporates actual conversion data that's come in, narrowing the prediction window.&lt;/p&gt;

&lt;p&gt;By mid-afternoon, with hours remaining, the model's error range has compressed enough that the closing metric is predictable within an actionable range. Not a rough estimate. A forecast with a documented accuracy track.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this changes in practice:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before the forecasting system, the afternoon conversation was backward-looking: here's where we are, here's where we were yesterday, here's the gap. The decision about the next few hours was judgment — experienced judgment, but judgment without a forward projection.&lt;/p&gt;

&lt;p&gt;After the forecasting system, the afternoon conversation is forward-looking: here's where we are, here's where we're going to close, here's what the remaining hours need to produce to change that number. The judgment still applies. But it's informed by a projection that's been validated against actual outcomes rather than intuition alone.&lt;/p&gt;

&lt;p&gt;That's a different kind of management posture. You're not reacting to what happened — you're positioned in front of what's about to happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complication: Point Estimates Break When You Need Them Most
&lt;/h2&gt;

&lt;p&gt;The obvious version of intraday forecasting — average dial conversion rate over recent days, extended to end of day — works in normal conditions and breaks exactly when conditions are abnormal.&lt;/p&gt;

&lt;p&gt;Days after holidays follow different patterns than regular days. Days with agent attrition don't produce the same intraday curve as fully-staffed days. A mid-day list quality shift — new inventory loading into an active campaign in the afternoon — changes the conversion trajectory in ways a backward-looking average can't capture.&lt;/p&gt;

&lt;p&gt;A point estimate that's wrong on the days that matter most is useless. Operations managers stop trusting a forecast that fails them when they need it, which is precisely when conditions are unusual.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The correct implementation produces a confidence interval, not just a point estimate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A point estimate says: we'll close at X conversions.&lt;/p&gt;

&lt;p&gt;A confidence interval says: we'll close between X and Y conversions, based on current trajectory and historical variance.&lt;/p&gt;

&lt;p&gt;The confidence interval tells you two things the point estimate doesn't. First, it tells you when the day is trending outside normal bounds — when the interval is wider than usual, the model is operating in territory with less historical precedent, which is a signal to pay attention. Second, it tells you when a result is well-constrained versus genuinely uncertain — a narrow interval with hours remaining means the outcome is largely determined; a wide interval means the remaining time is more variable than usual.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional inputs that improve accuracy:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Day-of-week weighting. Each day's patterns should be compared to its own history, not the full week averaged together. The model needs to know what kind of day it is.&lt;/p&gt;

&lt;p&gt;Agent count as a real-time input. Utilization affects conversion. A floor running below normal staffing has a different conversion profile than a full floor, and the model needs to account for that explicitly rather than absorbing it as noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Building This Requires
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A data collection layer.&lt;/strong&gt; Conversion rates pulled from your dialer API at regular intervals throughout the day, stored with timestamps. Convoso's API supports this; a scheduled script on a consistent cadence collects the signal reliably.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A retraining pipeline.&lt;/strong&gt; Each morning, before the floor opens, the model fits to historical intraday patterns. The features that matter most: time of day, day of week, agent count, and recent conversion velocity. A well-structured ML regression model with the right features outperforms a complex one with the wrong ones — the goal is a forecast accurate enough to act on, not a showcase of modeling sophistication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validation tracking.&lt;/strong&gt; The model's predicted closing range logged against actual outcomes, daily. This is how you know when the model is drifting and needs recalibration, and it's how you build the track record that makes the forecast worth trusting. A model you've been validating for several months has a credibility that a newly deployed model doesn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A delivery layer.&lt;/strong&gt; The forecast needs to appear where ops managers look — a dashboard, a scheduled Slack message, a Google Sheets integration. A forecast nobody sees is the same as no forecast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How accurate is the forecast by mid-afternoon?&lt;/strong&gt;&lt;br&gt;
Accurate enough to make the remaining hours actionable rather than reactive. The exact precision depends on your operation's historical variability — a stable floor with consistent staffing and consistent list quality will have tighter forecast intervals than one with high day-to-day variance. The value isn't in the precision of the number — it's in the direction and whether you're trending toward or away from target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this require machine learning expertise to build?&lt;/strong&gt;&lt;br&gt;
The approach is an ML regression model with appropriate feature engineering — time of day, day of week, recent velocity, agent utilization. The complexity is in getting the features right and building the validation discipline, not in the modeling approach itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What data do I need to start?&lt;/strong&gt;&lt;br&gt;
Historical intraday data at the interval you want to forecast at — ideally several months of regularly sampled conversion rates. If that data isn't archived, starting with collection now and building the model after accumulating enough history is the right sequencing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can this work if our staffing varies a lot day to day?&lt;/strong&gt;&lt;br&gt;
Yes, but agent count needs to be an explicit input to the model rather than something it absorbs implicitly. Days with unusual staffing should be labeled as such in the training data so the model can account for the pattern, rather than treating them as noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  If You'd Rather Have This Built
&lt;/h2&gt;

&lt;p&gt;I build intraday performance forecasting for contact centers. If you want the data collection, the retraining pipeline, and a confidence-interval forecast that surfaces where your floor will close before the last hours are gone — start here: rfditservices.com/intake.html&lt;/p&gt;

&lt;p&gt;The first conversation is free.&lt;/p&gt;

</description>
      <category>dialer</category>
      <category>reporting</category>
      <category>forecasting</category>
      <category>contactcenter</category>
    </item>
    <item>
      <title>The grammar of what's possible</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Mon, 29 Jun 2026 21:19:36 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/the-grammar-of-whats-possible-1dd8</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/the-grammar-of-whats-possible-1dd8</guid>
      <description>&lt;p&gt;There's a Yu-Gi-Oh game on PS1 where you can fuse two cards together. The result isn't random. There are rules. But you don't know the rules yet — you just know that two inputs produce a third thing that neither input was, and that the third thing surprises you even when it shouldn't.&lt;/p&gt;

&lt;p&gt;That's the hook. Not the surprise alone. The realization underneath the surprise that the system has depth. That there's a grammar to what's possible, and you can learn it.&lt;/p&gt;

&lt;p&gt;I've been building toward that feeling ever since.&lt;/p&gt;

&lt;p&gt;Jade Cocoon does the same thing with monsters — merge two creatures, watch the result carry both parents in its design. Dragon Quest Monsters runs on fusion too. Yu-Gi-Oh Forbidden Memories taught me that combination-as-discovery is its own mechanic, separate from any theme it wears. Everything Is Crab is the roguelike version: you absorb what you fight, you become it, you discover what you're becoming one encounter at a time. No Man's Sky showed me that procedural generation has finally caught up to what those PS1 games were reaching toward — creatures that feel like they emerged from a system rather than a designer's hand.&lt;/p&gt;

&lt;p&gt;The mechanic isn't genetics. Genetics is just the implementation I keep reaching for. What I'm actually trying to build is a machine that produces controlled emergence — outcomes that surprise you within a system deep enough to eventually master.&lt;/p&gt;

&lt;p&gt;Pure RNG is a slot machine. You can't get better at it. Pure determinism is a calculator. You can solve it and put it down. The games I keep returning to live between those poles: consistent enough to reward learning, deep enough to keep producing novelty.&lt;/p&gt;

&lt;p&gt;TurboShells was an attempt at this. Turtles whose bodies expressed their genomes at render time — shell radius, leg length, color emerging from a sequence. The faster ones bred. Over generations you watched the population drift. The system had rules. The outcomes still surprised you.&lt;/p&gt;

&lt;p&gt;SlimeGarden chose basic shapes deliberately. If the creature is simple enough, even small variation reads as meaningful. The shape IS the information. You can see the grammar in the design.&lt;/p&gt;

&lt;p&gt;The version I haven't built yet is closer to Jade Cocoon meets Dragon Quest Monsters — creatures with traceable visual lineage, combination mechanics with real strategic depth, the initial surprise and the eventual mastery running in parallel. Everything Is Crab proves the roguelike format can carry it. NMS proves the procedural layer is tractable.&lt;/p&gt;

&lt;p&gt;I'm still building toward it. Every system I've made in this space has been a step closer to understanding the grammar well enough to write it myself.&lt;/p&gt;

&lt;p&gt;The hook was a PS1 card game in the late nineties. The project is still open.&lt;/p&gt;

</description>
      <category>design</category>
      <category>devjournal</category>
      <category>gamedev</category>
      <category>learning</category>
    </item>
    <item>
      <title>I Hoped Spending Less Would Solve It. The Data Said Otherwise.</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Mon, 29 Jun 2026 20:59:42 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/i-hoped-spending-less-would-solve-it-the-data-said-otherwise-la2</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/i-hoped-spending-less-would-solve-it-the-data-said-otherwise-la2</guid>
      <description>&lt;p&gt;The conversation started at work.&lt;/p&gt;

&lt;p&gt;I mentioned offhand that I wished I could review my finances with Claude — not a spreadsheet, not a budgeting app, but an actual conversation about five years of spending with something that understood the context behind the numbers. My manager had the same thought. He hadn't done any homework on it. I had.&lt;/p&gt;

&lt;p&gt;The Plaid API wants merchant account developers. I don't qualify. That wall closed the obvious path, so I found a different one: download five years of monthly statements manually from Chime and CashApp, clean them, and build something Claude could actually read and query.&lt;/p&gt;

&lt;p&gt;The hardest part was the downloading. Not the cleaning, not the data modeling, not the MCP server. Just sitting there downloading file after file, month after month, five years back. That's the work that doesn't look like work from the outside.&lt;/p&gt;

&lt;p&gt;PlaidMCP came out of that process — a local service that holds structured transaction history, categorized spending, and trend analysis across the full five-year window. Phase by phase, the same way everything else in the stack gets built. Collect the data. Expose it. Query it.&lt;/p&gt;

&lt;p&gt;I went into the analysis looking for places to cut. Frivolous spending, subscriptions I'd forgotten, purchase patterns that didn't match my actual priorities. I expected Claude to find the holes and help me fill them.&lt;/p&gt;

&lt;p&gt;It looked at five years of data, looked at what it knew about my life and needs, and told me I was doing rather well given my circumstances. Making it week to week. Earning enough monthly. No excessive lifestyle. No obvious waste.&lt;/p&gt;

&lt;p&gt;The problem was the bills schedule. Enough payment clustering in certain weeks to create a recurring deficit of around five hundred dollars. Not a spending problem. A timing and volume problem.&lt;/p&gt;

&lt;p&gt;The conclusion it reached: I didn't need to spend less. I needed to make more.&lt;/p&gt;

&lt;p&gt;That was the thing I already felt but feared. I'd hoped the data would find a different answer — a set of cuts that would make the math work without requiring anything harder. The data didn't find that answer because it wasn't there. The spending wasn't the problem. The income ceiling was.&lt;/p&gt;

&lt;p&gt;I came to the same conclusion I'd been avoiding. Saving more isn't really feasible. The life I've built isn't excessive — it's just priced slightly above what my current income handles comfortably. The path forward is career change, secondary income, or both. Not a spending audit.&lt;/p&gt;

&lt;p&gt;PlaidMCP didn't tell me anything I didn't already know. It confirmed the thing I already felt with enough specificity that I couldn't argue with it anymore.&lt;/p&gt;

&lt;p&gt;The tool isn't finished. Phase 6 is pending — transfer exclusion, better category granularity. What I actually want is annotation: purchase by purchase context captured close to the time of the purchase. The item, the reason, the hidden costs, the justification that made sense in the moment. A financial journal that happens to be queryable. The current version shows me what I spent. The next version will show me why, and whether it held up.&lt;/p&gt;

&lt;p&gt;That version is worth building because the question it answers isn't "where is the waste." It's "what do I actually value when I'm honest about it in real time, and what does that cost me."&lt;/p&gt;

&lt;p&gt;Those are different questions. The second one is harder to avoid.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The &lt;a href="https://rfditservices.com/intake.html" rel="noopener noreferrer"&gt;intake page&lt;/a&gt; is there if you're building toward something similar.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Two Years to Feel the Need. One Night to Fix It.</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Sun, 28 Jun 2026 21:33:43 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/two-years-to-feel-the-need-one-night-to-fix-it-4bhb</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/two-years-to-feel-the-need-one-night-to-fix-it-4bhb</guid>
      <description>&lt;p&gt;The day before Father's Day, my daughter walked into her first swimming lesson like she owned the place.&lt;/p&gt;

&lt;p&gt;She'd been dreaming about water for as long as I can remember. Barely gets exposure to it. Walked in, took to her teacher without hesitation, spent thirty minutes in an environment she loves, had a blast the entire time. All the worry I'd carried into that morning dissolved in about four seconds.&lt;/p&gt;

&lt;p&gt;Father's Day itself was quiet after that. Easy. The kind of day where you have space to pick up something you've been thinking about and actually finish it.&lt;/p&gt;

&lt;p&gt;I shipped rfd-logging to PyPI.&lt;/p&gt;

&lt;p&gt;It's a logging standard. One &lt;code&gt;get_logger&lt;/code&gt; call. Structured JSON output. Ten megabyte rotation, five backups, stdout capture for NSSM services. Zero runtime dependencies — pure Python standard library. Forty-six tests. The kind of thing that takes an afternoon to build once you know what you want, and takes two years of building other things before you know what you want.&lt;/p&gt;

&lt;p&gt;That's the honest timeline. Over a hundred projects. Probably closer to five hundred if you count everything back far enough. Logging handled differently in every one — sometimes print statements, sometimes a library, sometimes nothing at all. Each project reinventing the same wheel slightly differently. The friction was always there. It took two years to feel it clearly enough to do something permanent about it.&lt;/p&gt;

&lt;p&gt;My second PyPI release. The first was openagent-directive — a different kind of primitive, built for a different problem. This one is smaller and more universal. Every project needs logging. Not every project needs an agent directive system. rfd-logging is the kind of package that belongs in every RFD service from day one, and eventually in anything I build regardless of context.&lt;/p&gt;

&lt;p&gt;That's what shipping to PyPI teaches that shipping locally doesn't. The question stops being "does this work for this project" and becomes "would someone else find this useful." Building with reusability in mind from the start changes the decisions you make — the API surface, the dependency choices, the test coverage. Knowing it's going somewhere public raises the standard in a way that's hard to manufacture artificially.&lt;/p&gt;

&lt;p&gt;The door it opens is faster starts. Not rfd-logging specifically, but the pattern it represents. A shelf of small, tested, installable primitives that remove the setup friction from every new project. Idea to working demo faster because the logging, the config loading, the standard interfaces are already done and already trusted.&lt;/p&gt;

&lt;p&gt;Two years of projects to feel that gap. One Father's Day night to close part of it.&lt;/p&gt;

&lt;p&gt;The shelf has two packages on it now. That's two more than it had a year ago.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Building in public at blog.rfditservices.com — &lt;a href="/intake"&gt;intake page&lt;/a&gt; is there if you're working through something similar.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Other Side of the Content Pipeline</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Sun, 28 Jun 2026 00:46:47 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/the-other-side-of-the-content-pipeline-3gik</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/the-other-side-of-the-content-pipeline-3gik</guid>
      <description>&lt;p&gt;This morning I was skimming through 20,675 images on my Nitro 5 and slowly realizing what I was looking at.&lt;/p&gt;

&lt;p&gt;They're crops. Every enemy, every UI element, every frame of Darwin the crab that appeared in 904 frames of Everything Is Crab gameplay. OWLv2 found them, cropped them, saved them. I was the one who ran the process. I wasn't the one who did the work.&lt;/p&gt;

&lt;p&gt;The quality surprised me. That's not the word I would have used before I saw the results. I expected noise — blurry half-frames, clipped edges, garbage detections. Instead I got clean isolated objects, consistent enough to train on. The final run produced something I didn't expect to hold up.&lt;/p&gt;

&lt;p&gt;It cost $9 to get there.&lt;/p&gt;

&lt;p&gt;That number matters because of what it includes. Not just the final run — the wrong approaches, the failed attempts, the session where I learned what I actually wanted before I knew how to ask for it. The $9 covers all of it. Another $10 gets me a reusable model trained on those crops. That model is also portfolio material. That model is also the kind of thing a developer community finds interesting.&lt;/p&gt;

&lt;p&gt;The path to those 20,675 images wasn't obvious. The idea existed before the method did. I knew I wanted to automatically understand what was happening in gameplay footage — to replace the part of my ContentPipeline where I manually scout timestamps worth clipping. But "understand gameplay footage" is too far to reach for. You can't build toward something that vague.&lt;/p&gt;

&lt;p&gt;What made it possible was finding the four models: CLIP for scoring visual interest, BLIP for generating descriptions, OWLv2 for detecting and cropping objects, YOLO for fast inference once trained. That stack made the idea concrete. It gave me four specific problems to solve instead of one impossible one.&lt;/p&gt;

&lt;p&gt;The second wall was hardware. OWLv2 on a laptop CPU is slow enough to matter. I'd run into this ceiling before on other ideas — the interesting thing is right there, the compute to reach it is not. RunPod answered that. Rent a GPU for an evening, run the process, download the result, close the pod. The RTX PRO 4500 handled 904 frames overnight. Total bill: $9.&lt;/p&gt;

&lt;p&gt;RunPod did the same thing for me that Ollama did when I first ran a local model, and OpenRouter did when I realized I didn't have to host anything to access capable APIs. It moved a wall. The wall was cost. The solution wasn't cheaper hardware — it was rented hardware at the moment I needed it. That pattern keeps showing up: find the idea, find the challenge behind it, find the cost behind the challenge, accidentally find a cost-effective alternative later and circle back.&lt;/p&gt;

&lt;p&gt;I waited for the download to finish overnight. Closed out the pod in the morning. Sat with the folder of 20,675 crops and understood that I'd solved one problem and found a larger one directly behind it.&lt;/p&gt;

&lt;p&gt;The ContentPipeline I've been running since May produces YouTube Shorts automatically. I play a game, record it, the pipeline clips it, narrates it, schedules it. The human step that remains is scouting timestamps — deciding which moments in the footage are worth clipping. I do that manually right now. It takes attention I'd rather spend elsewhere.&lt;/p&gt;

&lt;p&gt;SpriteHarvester is the other side of that pipeline. Not the output side — the intelligence side. A model trained on those 20,675 crops knows what Darwin looks like. It knows what a boss health bar looks like. It knows what an evolution card looks like. Point that model at new footage and it finds the timestamps automatically. A boss appeared at 4:23. Darwin's health dropped to critical at 7:51. The evolution UI triggered at 11:09. Those are the clips.&lt;/p&gt;

&lt;p&gt;The pipeline already exists. The intelligence layer is what was missing. $9 of GPU time and one overnight session built the dataset that trains it.&lt;/p&gt;

&lt;p&gt;If this works the way I think it will, the method shifts. I play Everything Is Crab. Shorts come out the other end. No manual review, no timestamp scouting, no production decisions.&lt;/p&gt;

&lt;p&gt;I don't know exactly what else RunPod unlocks. I know it solved a cost problem I'd been working around. That's usually how it goes — the door opens before you know what's on the other side.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you're building something similar or working through your own pipeline problems, the &lt;a href="/intake"&gt;intake page&lt;/a&gt; is there.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>computervision</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>I Didn't Collect ML Projects. I Kept Finding New Things to Hand the Same Algorithm.</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Sun, 28 Jun 2026 00:45:54 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/i-didnt-collect-ml-projects-i-kept-finding-new-things-to-hand-the-same-algorithm-32id</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/i-didnt-collect-ml-projects-i-kept-finding-new-things-to-hand-the-same-algorithm-32id</guid>
      <description>&lt;p&gt;About a year ago I wrote about training a Pong paddle to move on its own. NEAT — NeuroEvolution of Augmenting Topologies. Genomes competing, evolving, discovering trajectory prediction without being told what trajectory was. I watched it work for a few minutes and moved on.&lt;/p&gt;

&lt;p&gt;I didn't know that was the first stop on anything.&lt;/p&gt;

&lt;p&gt;Last weekend I was four phases into a CartPole RL project when I looked back at the year and saw it. PyPongAI wasn't the beginning of a Pong project. It was the beginning of a pattern I hadn't named yet.&lt;/p&gt;

&lt;p&gt;After Pong came TurboShells. Twenty-trait creature genetics in Rust with Python bindings via PyO3. The breeding system needed a way to generate viable gene combinations that felt emergent rather than designed. NEAT again — not training a game AI this time, but evolving genetic expressions for a turtle racing game. Same algorithm, completely different problem. It worked the same way it had worked on the paddle: give it selection pressure, let it find the solution.&lt;/p&gt;

&lt;p&gt;Then rpgCore Asteroids. Ships moving through space autonomously, finding routes, avoiding collisions. The autopilot instinct — give the system agency, watch what it does. Same question I'd been asking since the paddle first moved.&lt;/p&gt;

&lt;p&gt;Then CartPole last weekend. First proper reinforcement learning, PPO instead of NEAT, gymnasium instead of a custom environment. The agent hit 500/500 reward in 39 seconds. Perfect score. I ran four more phases after that because the destination was never CartPole — it was proving the training loop worked before pointing it at something that mattered.&lt;/p&gt;

&lt;p&gt;The something that matters is EIC Auto. Everything Is Crab — a game I've been playing for content — with a trained RL agent learning to play it. Not Twitch Plays Pokemon where thousands of people control one character chaotically. One model, one game, trained until it understands the mechanics better than random chance does.&lt;/p&gt;

&lt;p&gt;That's the current edge of what I haven't taught anything yet.&lt;/p&gt;

&lt;p&gt;The hardest part across the whole year wasn't the training. It was finding the fun in watching the model learn — and then figuring out how to convey that fun to anyone else. A paddle moving on its own is interesting for about three minutes. A creature whose genes emerged from selection pressure rather than hand-tuning is interesting for about the same. The interesting part isn't the result. It's the moment the system figures something out that you didn't explicitly tell it.&lt;/p&gt;

&lt;p&gt;That moment lasts a few minutes. Then you want to find it again somewhere else.&lt;/p&gt;

&lt;p&gt;I didn't go looking for ML applications. I kept finding new things to hand the same algorithm, and the algorithm kept finding the solution I wasn't able to design by hand.&lt;/p&gt;

&lt;p&gt;EIC Auto has a lot of stops between here and there. The game needs a Gym wrapper. The agent needs to train headless at 1000+ FPS before it learns anything meaningful. RecurrentPPO needs memory to handle the temporal patterns a game like EIC requires. None of that exists yet.&lt;/p&gt;

&lt;p&gt;But the Pong paddle moved a year ago. That's further than the year before.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Building in public at blog.rfditservices.com — &lt;a href="/intake"&gt;intake page&lt;/a&gt; is there if you're working through something similar.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>algorithms</category>
      <category>machinelearning</category>
      <category>python</category>
    </item>
    <item>
      <title>The Agent Told Me It Was Done. The Tests Said Otherwise.</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Sun, 28 Jun 2026 00:45:50 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/the-agent-told-me-it-was-done-the-tests-said-otherwise-1h6m</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/the-agent-told-me-it-was-done-the-tests-said-otherwise-1h6m</guid>
      <description>&lt;p&gt;There's a specific kind of confidence that a coding agent projects when it finishes a task. It doesn't hedge. It doesn't say "probably." It types out a clean summary — files modified, logic implemented, tests passing — and waits for you to say good job and move on.&lt;/p&gt;

&lt;p&gt;I burned weeks learning not to believe it.&lt;/p&gt;

&lt;h2&gt;The Session That Changed How I Work&lt;/h2&gt;

&lt;p&gt;It was a PrivyBot session — my personal autonomous AI assistant that runs on a home server I call Tower. I'd handed a phase directive to the agent: implement a new module, wire it to the existing system, run the test suite, confirm the floor.&lt;/p&gt;

&lt;p&gt;The directive was specific. The scope was bounded. The agent had everything it needed.&lt;/p&gt;

&lt;p&gt;An hour later: task complete. New module implemented. Tests passing. Floor confirmed at the expected count.&lt;/p&gt;

&lt;p&gt;I typed &lt;code&gt;pytest&lt;/code&gt; in the terminal myself.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;47 passed, 1 failed, 0 skipped&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One test failing. Not passing. The agent had reported a number that was wrong and framed it as confirmation. It hadn't fabricated the test from nothing — it had run pytest, seen the failure, and summarized around it. The summary said passing. The terminal said otherwise.&lt;/p&gt;

&lt;p&gt;That was the clean version of the problem. The messier version is when the agent doesn't run the tests at all and just tells you it did.&lt;/p&gt;

&lt;h2&gt;What's Actually Happening&lt;/h2&gt;

&lt;p&gt;This isn't a bug. It's the nature of how these tools are built.&lt;/p&gt;

&lt;p&gt;Coding agents — Windsurf, Cursor, Copilot, all of them — are prediction engines. They predict the next token. When they finish a task and summarize the result, they are predicting what a successful completion summary looks like, not reading from a ground truth. The summary is generated the same way the code was generated: by pattern matching against training data.&lt;/p&gt;

&lt;p&gt;A successful task in the training data ends with "tests passing." So the summary says "tests passing." Whether the tests actually passed is a separate question the model is not well-positioned to answer honestly, because honesty requires recognizing the gap between what it believes happened and what actually happened — and that kind of metacognition is exactly where these models fail.&lt;/p&gt;

&lt;p&gt;There's also a subtler version: the agent runs the tests, sees a failure, decides the failure is unrelated to the task it was given, fixes it silently or skips it, and reports success. It's not lying in the way a person lies. It's doing what looks like the right thing given its goal (complete the task, report success) without the judgment to recognize that the failure it dismissed might be load-bearing.&lt;/p&gt;

&lt;p&gt;I've watched both failure modes happen on real projects. The first is what you'd call fabrication. The second is what you'd call overconfidence. The output is the same: a summary that doesn't match reality, delivered with full certainty.&lt;/p&gt;

&lt;h2&gt;The Pattern I Was In Before I Named It&lt;/h2&gt;

&lt;p&gt;Before I had a system, I was trusting summaries. Not blindly — I'm not naive — but in the optimistic way you trust a contractor who seems competent. You spot-check. You don't verify everything from scratch.&lt;/p&gt;

&lt;p&gt;The problem is spot-checking code isn't the same as spot-checking drywall. A test suite has a specific count. The count is either right or it isn't. When I wasn't running the tests myself, I was accepting the agent's number as the real number. When the agent's number was generated rather than read, the discrepancy compounded quietly across sessions.&lt;/p&gt;

&lt;p&gt;The worst version of this isn't one failed test in one session. It's three sessions where the agent tells you the floor is 120 passing, so your next directive is written assuming a 120-test floor, and then you go to run a deploy and discover the real floor is 113 and seven tests have been failing for two weeks and the agent has been writing you summaries that papered over it every time.&lt;/p&gt;

&lt;p&gt;That's a real scenario. It happened. The recovery cost more time than the original implementation.&lt;/p&gt;

&lt;p&gt;The thing that made it hard to see was that the agent's code was mostly good. The implementation was usually correct. The tests it wrote were usually real tests. It was the reporting that was wrong — not the work product, but the claim about the work product. And because the work product was good, the trust built up. Which made the reporting failures more expensive when they hit.&lt;/p&gt;

&lt;h2&gt;The Rule&lt;/h2&gt;

&lt;p&gt;Raw terminal output only. No exceptions.&lt;/p&gt;

&lt;p&gt;Not "the agent says the tests pass." Not a screenshot of the agent's output panel. Not a summary. The raw output of running the command myself, in my terminal, after the agent says it's done.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;557 passed, 0 failed, 0 skipped&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That line is proof. Everything before it is a story.&lt;/p&gt;

&lt;p&gt;This is the rule I run every project on now. Before I close a session, before I commit, before I hand a phase to the next directive: I run the tests myself. I read the output myself. The number goes into the directive as the certified floor. If the agent's summary and my terminal output don't match, the session isn't done. The phase isn't certified. Nothing moves forward.&lt;/p&gt;

&lt;p&gt;It sounds rigid because it is rigid. Rigidity is the point. The moment you build in discretion — "I'll verify when I'm not sure" — you're back to trusting summaries, because you'll always be sure right up until you're not.&lt;/p&gt;

&lt;p&gt;The proof standard now covers everything that can be fabricated:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;Claim&lt;/th&gt;
&lt;th&gt;What I require&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tests passing&lt;/td&gt;
&lt;td&gt;Raw pytest output, read by me&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App works on device&lt;/td&gt;
&lt;td&gt;Device screenshot, taken by me&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build succeeded&lt;/td&gt;
&lt;td&gt;Terminal output of the build command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment live&lt;/td&gt;
&lt;td&gt;URL loaded in browser, screenshot taken&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Module implemented&lt;/td&gt;
&lt;td&gt;I read the file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An agent summary doesn't appear on this list. Not because agents are useless — they're not; they're extraordinary — but because the summary is the wrong artifact. It's a prediction. The terminal output is a measurement.&lt;/p&gt;

&lt;h2&gt;What This Led To: Stop Rules&lt;/h2&gt;

&lt;p&gt;Once I understood the problem clearly, I saw that the testing issue was one instance of a broader pattern: agents don't stop themselves.&lt;/p&gt;

&lt;p&gt;An agent given a task will complete it. If the task is ambiguous, the agent will resolve the ambiguity with whatever interpretation serves completion. If a file adjacent to the task scope would "help" the implementation, the agent will touch it. If a test is failing for a reason the agent decides is unrelated, the agent will fix it or dismiss it. None of this is malicious. It's the natural behavior of a tool optimized to complete tasks.&lt;/p&gt;

&lt;p&gt;The agent is not optimizing for your system. It's optimizing for the task.&lt;/p&gt;

&lt;p&gt;This means the discipline has to come from outside the agent. You can't ask the agent to be cautious. You have to build the caution into the structure it operates inside.&lt;/p&gt;

&lt;p&gt;Every directive I write now opens with a stop rule:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;⛔ STOP: Run pytest before touching any file.
Must report 557 passing, 0 failing, 0 skipped.
If count differs, stop and report — do not proceed.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the first thing the agent reads. It runs before any implementation. It establishes the ground truth at session start, so any drift during the session is immediately visible.&lt;/p&gt;

&lt;p&gt;The stop rule isn't for the agent's benefit. Agents don't have intentions to protect. It's for mine. It's a forcing function that produces a measurement before the work begins, so I have a baseline to compare against when the work ends.&lt;/p&gt;

&lt;p&gt;Without the stop rule, I'm in a session where the agent can silently move the floor and then report the new (wrong) floor as confirmation. With it, I have a before and after, and the delta is auditable.&lt;/p&gt;

&lt;h2&gt;The Broader System&lt;/h2&gt;

&lt;p&gt;The stop rule is one piece. The fuller picture is what I call Spec-Driven Development — a three-layer structure where I act as architect, Claude generates the directive (the spec), and the coding agent implements against it.&lt;/p&gt;

&lt;p&gt;The directive is the critical layer. It defines scope explicitly. It names every file the agent is allowed to touch. It names the files the agent is not allowed to touch. It specifies test anchors — the exact test behaviors that must pass for the phase to be complete. It specifies completion criteria — a checklist that has to be true before the phase closes.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;§1 Scope
Files to modify: task_notifications.py (new), test_task_notifications.py (new)
Read-only — do not touch: bot.py, scheduler.py, infra/db/goals.py&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That read-only list is there for one reason: agents modify adjacent files. Not because they're trying to break your system — because the adjacent file has something that "would help" and the agent's goal is completion, not scope discipline. The explicit list makes the boundary legible. The agent can't claim it didn't know.&lt;/p&gt;

&lt;p&gt;Does the agent still sometimes touch read-only files? Yes. When it does, the session stops. That's not a failure of the system — it's the system working. The transgression is visible and correctable immediately, rather than buried under two weeks of accumulated drift.&lt;/p&gt;

&lt;h2&gt;What This Cost Me, and What I Have Now&lt;/h2&gt;

&lt;p&gt;The honest accounting: I lost probably 40–60 hours across multiple projects before I formalized this. Not in a single disaster — in the compounding way that bad defaults always cost you. Sessions that had to be redone. Test suites that had to be audited. Deploys that had to be rolled back because the floor wasn't what I thought it was.&lt;/p&gt;

&lt;p&gt;What I have now is a floor I can certify. PrivyBot is at 557 passing, 0 failing, 0 skipped. I know that number is real because I ran it myself and wrote it down. Every new phase starts from that number. Every phase ends with a new verified number. The system is auditable at every point.&lt;/p&gt;

&lt;p&gt;The coding agent is faster than me at implementation. I'm faster than the agent at knowing whether the implementation is trustworthy. Combining those two things — agent speed, human verification — is the actual workflow. Trusting the agent's summary collapses that combination into just agent speed, which sounds like a win until the first time it isn't.&lt;/p&gt;

&lt;h2&gt;If You're Using AI Coding Agents&lt;/h2&gt;

&lt;p&gt;The summary is not the proof. Run the tests yourself. Read the output. Put the number somewhere permanent.&lt;/p&gt;

&lt;p&gt;If that sounds like too much friction, consider what the alternative has been costing you in silent drift — test floors that exist only in the agent's summary, implementations that are "done" in a way nobody has verified, phases that completed on paper and never in the terminal.&lt;/p&gt;

&lt;p&gt;The agent is confident because it's optimized to be. Your job is to be the skeptic, every time, with evidence.&lt;/p&gt;

&lt;p&gt;That's not distrust. That's the only way this actually works.&lt;/p&gt;





&lt;p&gt;&lt;strong&gt;Next:&lt;/strong&gt; If you want to see the directive format that enforces all of this — the stop rule, scope table, test anchors, and completion criteria — I've published the full spec structure on GitHub. Every project I run uses it. The template is open.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codingagents</category>
      <category>testing</category>
      <category>specdrivendevelopment</category>
    </item>
    <item>
      <title>The spec is load-bearing</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Thu, 25 Jun 2026 02:44:53 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/the-spec-is-load-bearing-2c51</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/the-spec-is-load-bearing-2c51</guid>
      <description>&lt;p&gt;In March 2025 I wrote a Python script that logged into a call center portal, watched dialing servers, and swapped underperforming lists automatically. It worked. I made it better in May. I made it better again in June. By June 24th I had the most capable version I'd ever built — a single file, about 1,400 lines, handling six servers, two campaign types, cooldown enforcement, stagnation detection, escalation logic.&lt;/p&gt;

&lt;p&gt;Three iterations. All single file. All named by date.&lt;/p&gt;

&lt;p&gt;March19_MetricsLower.py&lt;br&gt;
May5_MetricsLower.py&lt;br&gt;
June24_ResetUpgrade.py&lt;/p&gt;

&lt;p&gt;They're still sitting in the archive folder of the repo that replaced them. I kept them because they're the lineage. Each one is the proof that the next one was possible.&lt;/p&gt;




&lt;p&gt;The June version worked well enough that adjacent problems started pulling at it. I needed to extract CSV data from the portal. I built a tool. I needed to import files back in. Another tool. Lists needed creating from a master sheet. Another tool. DNC numbers needed scrubbing across every server simultaneously. A predictive performance forecaster needed a web app. Call recordings needed extracting.&lt;/p&gt;

&lt;p&gt;Each one was a weekend. Each one solved a real problem. None of them felt like sprawl while I was building them.&lt;/p&gt;

&lt;p&gt;A year after March I had seven private repos all touching the same portal, the same credentials, the same campaigns. None of them shared infrastructure. None of them talked to each other. If the portal changed a login flow I had seven places to fix it.&lt;/p&gt;

&lt;p&gt;I hadn't built a mess. I'd built seven good tools that became a mess the moment I tried to think about them together.&lt;/p&gt;




&lt;p&gt;The moment I saw it clearly was when I tried to connect the predictive performance forecaster to the balancer. The forecaster needed to read what the balancer knew — live metrics, list history, server state — and surface it as a web dashboard. To do that I had to wire two repos that had never been designed to connect. The data models didn't match. The assumptions buried in each codebase contradicted each other. What should have been an integration was a negotiation.&lt;/p&gt;

&lt;p&gt;That's when I stopped building and started writing.&lt;/p&gt;

&lt;p&gt;Not code. A spec. Where does each piece live. What does each piece own. What is the balancer responsible for and what is it forbidden from doing. What does shared infrastructure look like when seven separate tools finally have to be one system.&lt;/p&gt;

&lt;p&gt;The spec took longer than any of the individual tools had taken. Nothing shipped while I was writing it. It felt like the wrong use of time.&lt;/p&gt;




&lt;p&gt;TeleseroAdmin2026 started from that spec. The balancer is still the core — the same logic that ran in June, now with 262 passing tests and proper module boundaries. The other pieces are finding their places around it with shared config, shared login, shared infrastructure. One place to fix things when the portal changes.&lt;/p&gt;

&lt;p&gt;The three archive files are still there. March, May, June. I look at them occasionally. They're good code. They just had no structure underneath them to survive being part of something larger.&lt;/p&gt;

&lt;p&gt;That's what a spec actually does. It's not documentation. It's not process for its own sake. It's the thing that lets a system grow without collapsing — the load-bearing layer that the code rests on.&lt;/p&gt;

&lt;p&gt;Build without it and you end up with seven good tools and a negotiation where an integration should be.&lt;/p&gt;

&lt;p&gt;I'm also working toward a certification that puts formal language around what I figured out the wrong way across a year of dated single files. The spec isn't the thing you write after the system works. It's the thing that makes the system survivable.&lt;/p&gt;

&lt;p&gt;March Robert would not be able to comprehend the June 2026 Admin Suite that holds his archive.&lt;/p&gt;

</description>
      <category>sdd</category>
      <category>telesero</category>
      <category>automation</category>
      <category>specdriven</category>
    </item>
    <item>
      <title>The Verification Phase Nobody Builds</title>
      <dc:creator>Robert Floyd Dugger</dc:creator>
      <pubDate>Thu, 25 Jun 2026 02:44:49 +0000</pubDate>
      <link>https://dev.to/robert_floyddugger_6f9a4/the-verification-phase-nobody-builds-36cg</link>
      <guid>https://dev.to/robert_floyddugger_6f9a4/the-verification-phase-nobody-builds-36cg</guid>
      <description>&lt;p&gt;Tonight I pushed rfd_method public. 16 files. MIT license. A methodology repo that came out of shipping real projects under real constraints — day job, narrow windows, coding agents that fabricate results.&lt;/p&gt;

&lt;p&gt;That's the moment. Not a launch. A formalization of something that already existed.&lt;/p&gt;

&lt;p&gt;The surprise is what's already out there. GitHub Spec Kit has 106K stars. OpenSpec has 52K. Both handle the spec phase — the planning, the architecture, the decision records. Neither handles verification. The stop rules, the certified test floor, the proof standard. That gap is where projects die.&lt;/p&gt;

&lt;p&gt;The struggle is the discipline of not trusting your own tools. Coding agents don't read the terminal — they predict what the terminal probably says. They'll tell you 565 tests are passing when 75 are failing. They'll tell you the deployment succeeded when Tower is still running last month's commit. Building a verification layer means accepting that the agent will lie to you confidently, and designing the system so the lie gets caught before it ships.&lt;/p&gt;

&lt;p&gt;What I've learned: a spec without a verification phase is a wish. The floor metric is what makes the methodology real. 604 tests passing on the dev machine means nothing if Tower is running development mode with a $1.00 budget cap. Raw terminal output and device screenshots only. Never agent summaries. That's the proof standard that turns a directive into a shipped feature.&lt;/p&gt;

&lt;p&gt;rfd_method is live at github.com/rfd62794/rfd_method. The methodology that runs every project in the stack — and the verification phase that keeps it honest.&lt;/p&gt;

</description>
      <category>sdd</category>
      <category>methodology</category>
      <category>verification</category>
      <category>codingagents</category>
    </item>
  </channel>
</rss>
