[CODE]

One Checkpoint for Ads, Two for Code: Deciding Where the Human Belongs

Rewriting the ads-execute skill from a report-driven flow into an end-to-end operation where an AI agent does the diagnosis, the account changes, and the website coding — and the human reviews at exactly the points where review changes the outcome.

6 min read AI-generated
ai automation google-ads workflow-design claude-code

The old flow had Wayne in the loop at seven steps. The rewrite cut that to two — but not the same two for every kind of change.

This is one node in a larger system I’ve written about before: an ads engine for three B&B operators running five properties in Hengchun, where a weekly analysis agent flags problems and a set of skills turn those findings into real changes on the Google Ads account and, increasingly, on the websites themselves. The piece that changed this time is ads-execute — the skill that takes a problem and actually fixes it. What it does now is broader than it was, and the interesting decision isn’t the broadening. It’s where the human checkpoints landed.

The skill stopped being about reports

Originally, ads-execute had one entry point: you feed it an ads-health report, it parses the findings, and it turns them into account changes. That’s a clean contract, but it was too narrow for how the work actually happens. Half the time the problem doesn’t come from a report at all — it comes from a live conversation, where I’ve looked at the data with the agent and we’ve reached a conclusion together. There’s no artifact to feed in. The old skill had no way to execute that.

So the scope now covers two entry conditions: a health report, or a conclusion reached in real-time discussion with no report behind it. And the execution surface expanded past the Ads account to the website itself — the agent does the diagnosis, the classification calls (negative keyword vs. match-type fix vs. keyword harvesting vs. Final URL vs. a genuine site-content problem), the actual website code changes, and the verification. The whole point is that I run one command and mostly wait.

Why one checkpoint for the account and two for the site

Here’s the decision that matters. Ads-account changes and website code changes carry different risk profiles, and treating them identically would have been either too slow or too dangerous.

For Ads-account changes: one checkpoint. Every mutation goes through a git-tracked YAML file processed by ads-mutate.ts, or through ads-fix-final-url.ts — and both support a dry-run. A dry-run of a mechanical mutation isn’t a summary of what might happen; it’s the exact, itemized preview of what will happen. Once I’ve seen the dry-run output, there is nothing further to review. Diagnose, classify, generate the change plan, dry-run it, show me the dry-run as part of Checkpoint 1, and on approval, execute directly. A second look would be reviewing the same information twice.

For website code changes: two checkpoints. A written plan and an actual diff are not the same object, and the gap between them is where mistakes live. The agent first writes a plan in prose — no code touched — and that plan goes into Checkpoint 1 alongside the Ads dry-run. Only after I approve does it write the actual code, spin up a dev server, take screenshots, and then come back for Checkpoint 2 with the real diff and the screenshots. This is the second look the Ads path doesn’t need, because “here’s my plan” and “here’s what I actually wrote” are genuinely different claims for code in a way they aren’t for a mechanical account mutation.

That asymmetry is the whole design. The number of checkpoints isn’t a comfort setting — it’s calibrated to how much the review actually reveals. Reviewing an Ads dry-run twice tells you nothing new the second time. Reviewing a code plan and then the code diff tells you two different things.

The record that closes the loop

After execution, the skill writes the change into sites/<slug>/operator-events.yaml, and if the website was touched, updates the handoff and worklog docs too. This isn’t bookkeeping. The weekly analysis agent’s understanding of each site is a static context file — it knows what it was told the last time someone updated it, which can’t keep pace with how often interventions actually happen. That’s a structural gap: an AI evaluating last week’s results has no idea what changed last week unless something tells it.

operator-events.yaml is that something — a machine-readable, continuously-appended log of what was done and why. The next analysis run reads it, so the agent measuring outcomes already knows which interventions preceded them. Without it, the analyst would see inquiry volume move and have no way to attribute the cause — it would guess, and guess wrong. The record isn’t a memo for humans; it’s context injection for the next AI in the chain.

The guard that saves a wasted run

One small addition worth naming: if a site’s config is missing its Google Ads account block, the skill stops immediately at the top rather than letting the failure surface three scripts deep. Every downstream Ads script — snapshot, health-fetch, mutate — throws the same error when the account list is empty, and each of those failures is more confusing than the one that would have caught it at the source. Failing fast at the entry point, with the exact fix spelled out (add the 10-digit account ID to config, commit, restart), turns a cryptic mid-pipeline crash into a one-line instruction. It’s the difference between an agent flailing and an agent stopping cleanly.

Why this exists at all

The honest framing: this level of service — per-site diagnosis, account optimization, website fixes, and a structured audit trail feeding back into the next analysis — was never economically available to a small B&B. Each piece used to require its own headcount, and no B&B budget covers an engineer plus an analyst plus an ad manager. It’s not that someone chose not to build it; the math never worked.

What changed is that an AI agent can now hold the whole chain — diagnose, classify, execute across two surfaces, record — with a human surfacing only at the two points where a human genuinely changes the outcome. The design work isn’t making the agent capable. It’s deciding, precisely, where I still need to look.

One checkpoint where a dry-run tells you everything. Two where a plan and a diff tell you different things.