Skip to content

feat(leads): generate the pitch fields from a plain description of the goal - #149

Merged
ralyodio merged 1 commit into
masterfrom
feat/generate-pitch
Jul 28, 2026
Merged

ralyodio merged 1 commit into
masterfrom
feat/generate-pitch

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

The campaign form asks for three precisely-scoped inputs, and the grounding guard refuses drafts that stray outside them. That's a lot to ask of someone who just wants to describe what they're doing — and the failure is silent.

A live campaign had the same sentence pasted into both the intro and the ask, a facts list omitting the URL the ask depended on, and five rejected drafts a tick for hours as a result.

Describe the goal, get the fields

Verified on that exact campaign's text:

In: "Anthony owner of threatcrush.com we want to generate leads for people to download our free whitepaper at https://threatcrush.com/get-whitepaper"

Out:

INTRO  I'm Anthony, owner of threatcrush.com, and I'm reaching out because
       we've created a resource that might be useful to you.
ASK    Download our free whitepaper at https://threatcrush.com/get-whitepaper
FACTS  - threatcrush.com offers lifetime access to real-time threat intelligence
       - We have a free whitepaper available at https://threatcrush.com/get-whitepaper

Then, against the guard: a draft using the URL passes [], and "We have 4200 customers" is still rejected.

The first fact came from reading threatcrush.com's own site description — the one extra fact available without guessing, and exactly what someone omits describing a goal in a hurry.

It restructures; it does not author

This is why it can be trusted with the job. Drafts are checked against its output, so a fact invented here isn't caught later — it's laundered into something a stranger is told is true. The prompt refuses new numbers, links, dates and credentials, and refuses to embellish ("30 years as a software engineer" must not become "three decades of industry leadership").

Any URL the person wrote is forced into the facts in code afterwards, not trusted to the model — dropping one recreates exactly the failure this exists to prevent.

Also

The two guard messages disagreed — one said "not in the campaign's declared facts", the other "the campaign never mentions". After #148 widened the grounding set, the first was no longer true.

Checks

  • tsc --noEmit clean · 938/938 tests pass · build compiles
  • generator exercised live against the real campaign goal

🤖 Generated with Claude Code

…e goal

The campaign form asks for three precisely-scoped inputs — who is writing,
one small ask, and the checkable claims — and the grounding guard then
refuses drafts that stray outside them. That is a lot to ask of someone
who wants to describe what they are doing, and the failure it produces is
silent: a live campaign had the same sentence pasted into both the intro
and the ask, a facts list that omitted the URL the ask depended on, and
five rejected drafts a tick for hours as a result.

So the splitting is done here instead. Describe the goal in a sentence and
the three fields are filled in.

It restructures and does not author, which is the whole reason it can be
trusted with this job. Drafts are checked against its output, so a fact
invented here is not caught later — it is laundered into something a
stranger is told is true. The prompt refuses new numbers, links, dates and
credentials, and refuses to embellish a claim into a stronger one.

Any URL the person wrote is forced into the facts afterwards rather than
trusted to the model, because dropping one recreates precisely the failure
this exists to prevent.

The sender's own domain, when their goal mentions it, is read for how the
site describes itself. That is the one extra fact available without
guessing, and it is exactly what someone omits when describing their goal
in a hurry.

Also makes the two guard messages agree. One said a value was "not in the
campaign's declared facts" while the other said the campaign "never
mentions" it — and after the grounding set widened to include the intro
and ask, the first was no longer true.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit 2fb91fc into master Jul 28, 2026
8 checks passed
@ralyodio
ralyodio deleted the feat/generate-pitch branch July 28, 2026 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant