THE STAGE
WindowAug 30 to 31
Outbound: 12 emails, one per person, no follow-up, no tracking pixels
Nothing audits a pipeline like having to sign your name to it
The last mile of GTM engineering is not delivery. It is the point where you stop trusting your own output because someone else is about to read it. Errors in a pipeline built for yourself cost nothing. Errors sent under your real name have a name and an inbox attached.
Onboard: the outbound runA screen recording made during the build.Opens in a new tabStage log
Build log
Aug 30
The reply loop
217 lines of Google Apps Script. A labelled Gmail thread is found, stripped of quoted text, classified, and POSTed to a Clay webhook table in under 60 seconds on a one-minute trigger. The webhook URL lives in Script Properties and never appears in the file, because that URL is a secret and gets treated like a key.
Aug 30
The seed
12 rows, one per person. The seed carries no email column at all; addresses stay in the send system. Five guardrail states sit ahead of every send, including a personalization block that refuses anything under 40 characters of account-specific finding. The guardrail reports rather than locks, and SEND_OK is required.
Aug 31
Verified end to end
A labelled thread was found, parsed, classified and written to Clay with no human in the path. The architecture diagram below records the date.
Timing sheet
Metrics
- Sends
- 12One message per person. No follow-up, no tracking pixels.
- Work email coverage
- 12 of 12Source: working sessionAll resolved by the first provider in an 11-provider waterfall, so ten providers never fired. About 7 credits against an estimate of 13 to 25.
- Total spend across the stage
- ~508 creditsSource: working session126 HTTP, about 375 agent research, about 7 email.
- Reply latency
- under 60 secondsCapture is automatic. The join back onto the send row is manual, and the diagram says so.
- Replies
- 0Source: working sessionPre-registered expectation: 2 to 4 replies, 1 to 3 corrections, 0 to 1 meetings, 0 to 1 opt-outs. Zero is the actual outcome, so zero is the number on this page.
Source: working sessionNumbers marked with a dot come from the working session and its published posts. Unmarked numbers are stated in the build artifacts on disk, with file and line.
TELEMETRY VS DRIVER
The gate lost to hand research
The automated gate passed 57 of 199 accounts. Five of the twelve accounts I actually sent had been filed EXCL_SALES_LED by that gate, and every one of the five had verified in-house billing work anyway. The gate measured self-serve checkout. The research measured in-house metering. Run unsupervised, the gate would have cost five of the twelve best accounts, including one of the two high-confidence builders.

PARC FERMÉ
Twelve, when the brief allowed twenty-five
The volume cut came from the personalization bar rather than capacity. Only 12 accounts produced a finding specific enough to justify a send. One of the twelve findings is a bug report about my own scan, sent to the company anyway:
My crawler only ever saw useagave.com while the product, docs and login all live on agaveapi.com, so it never reached the surface where billing would be. That is a bug in my scan rather than a finding about Agave.
STEWARDS' NOTE
Where the line is
The best-researched contact in the build was an engineer at a company that sells subscription billing infrastructure. Their working email was sitting in git commit author metadata on a personal domain, and their public work was exactly what I would have been asking about.
I did not send, for two reasons. The company runs on the processor I was writing about, so the claim in my email would have been wrong, and wrong in a way that gets forwarded. And the address was never published as a contact channel. It leaked as a side effect of committing code. The same pattern came up twice more in the build, and I never used it.
Reading someone's commit history to find out what they built is fine. Reading it to find out where to reach them is something else, and both start with the same git log. The line is not in the data. It is in what you do next with it.
SCRUTINEERING
The seams, stated
Two things the tooling gets wrong about this build, published here because the paper trail should be better than the tool's. The reply join is manual: capture lands in Clay in under 60 seconds, but a Clay enrichment fires on changes to its own row and never on changes in the table it reads from, so the lookup back onto the send row is refreshed by hand. And Clay's lineage graph shows the send seed parented to a CSV rather than the source table. Every field traces back to the segment, and the lineage does not know that.

INCIDENT REPORT
What broke
Zero replies against a pre-registered expectation of 2 to 4. At twelve sends the sample is built to produce labelled corrections rather than pipeline, and a zero still gets published, in the same voice as everything else, because the alternative is a portfolio of only the runs that flattered me.

STAGE END
Debrief
The primary metric of the whole build is corrections received: a reply naming the actual billing stack is a labelled correction to the detection method. That is why the classifier machine-detects vendor names. And it is why opt-out is checked first anyway. Getting a data point does not override someone asking you to stop.

Service park
Artifacts
System architecture
classify_(), from the reply loop
/**
* First-pass classification. A human confirms it in Clay; this only
* saves the sorting. Order matters: opt-out beats everything.
*/
function classify_(lowerBody, lowerSubject, named) {
if (matchesAny_(lowerBody, OPTOUT_PATTERNS)) return 'opt_out';
if (matchesAny_(lowerSubject, OOO_PATTERNS) || matchesAny_(lowerBody, OOO_PATTERNS)) return 'auto_reply';
if (lowerSubject.indexOf('undeliverable') !== -1 ||
lowerSubject.indexOf('delivery status notification') !== -1 ||
lowerSubject.indexOf('mail delivery failed') !== -1 ||
lowerBody.indexOf('address not found') !== -1) return 'bounce';
if (named.length > 0) return 'correction';
return 'needs_review';
}