Skip to content

fix(sales): block retired offer copy in outbound send packages - #71

Merged
nish3451 merged 4 commits into
mainfrom
fix/outbound-send-retired-offer-gate
Aug 11, 2026
Merged

fix(sales): block retired offer copy in outbound send packages#71
nish3451 merged 4 commits into
mainfrom
fix/outbound-send-retired-offer-gate

Conversation

@nish3451

Copy link
Copy Markdown
Collaborator

What

The active prospect send package still sold the retired broad-agency offer. prepare-prospect-send.mjs embeds recording-notes.md verbatim into send-package.md, and recording-notes.md is user/fixture-provided — it can carry the retired "7-Day Site Revenue Fault Sprint with a 30-day action plan" ask. check-outbound-send-readiness.mjs only checked opt-out language and placeholders, so a stale send package passed CI while selling the retired offer.

Fix

  • scripts/check-outbound-send-readiness.mjs
    • Add the canonical retired-offer pattern (mirroring export-recording-rehearsal-check.mjs's RETIRED_ASK_PATTERNS) and scan send-package.md and recording-notes.md.
    • New finding rule: outbound package sells a retired offer.
  • scripts/test-outbound-send-readiness.mjs
    • Fixture coverage: a send package or recording-notes containing the retired 7-day sprint / 30-day action plan / $500 ask now fails the gate; canonical founder-pilot copy still passes.
  • scripts/test-active-offer-projection.mjs
    • Projection test now also runs send prep on the legacy fixture and asserts send-package.md contains only the canonical The Website Correction offer, no guarantee outcomes, and no retired-offer phrasing.

Verification

  • npm run ci exits 0.

Closes: active prospect send package still sells the retired 7-day sprint + 30-day action plan

The active prospect send package embeds recording-notes.md verbatim,
which can still carry the retired 7-Day Site Revenue Fault Sprint /
30-day action plan ask. check-outbound-send-readiness only checked
opt-out language and placeholders, so a stale recording-notes.md or
send-package.md sold the retired offer without any CI failure.

Add the canonical retired-offer pattern to the outbound send
readiness gate for send-package.md and recording-notes.md, and extend
the active-offer projection test to assert the generated send package
projects only the canonical founder-pilot offer.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@nish3451, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7766b5a3-b020-4148-98ff-d067f03a70fb

📥 Commits

Reviewing files that changed from the base of the PR and between f1565a7 and 8948f88.

📒 Files selected for processing (3)
  • scripts/check-outbound-send-readiness.mjs
  • scripts/test-active-offer-projection.mjs
  • scripts/test-outbound-send-readiness.mjs

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: df7f9a4807

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +130 to +132
if (["send-package.md", "recording-notes.md"].includes(filename) && retiredOfferPattern.test(content)) {
findings.push({ file, rule: "outbound package sells a retired offer" });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce the retired-offer check in the send flow

When an operator follows the documented prospect:send-prep or market:after-recording flow, neither send preparation nor export-prospect-outbox.mjs invokes this checker; the outbox admits packages based only on Loom approval and the existing readiness marker. Consequently, recording notes containing a retired pitch can still produce a ready package and an actionable outbox entry unless the operator separately remembers to run send:check, so this new rule does not actually block the unsafe send path.

Useful? React with 👍 / 👎.

const salesPlaceholderPattern = /\badd (?:meeting link|payment link|call time)\b/i;
// Retired broad-agency offers must never project into an outbound send package.
// Mirrors the canonical retired-ask guard in export-recording-rehearsal-check.mjs.
const retiredOfferPattern = /7[-\s]day (?:site|website) revenue (?:leak|fault) (?:fix )?sprint|tangible revenue (?:leak|fault) sprint|30[-\s]day action plan|growth desk|three pages|\$\s?500\b/i;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict retired-offer matching to the actual offer ask

Because this expression treats standalone three pages and $500 as retired offers and is tested against the entire send package or recording-notes file, legitimate prospect evidence such as “pricing starts at $500” or “navigation spans three pages” makes send:check fail with “sells a retired offer.” The rehearsal guard this is intended to mirror scopes the test to the ask; this gate should likewise inspect the clean-ask/message section or require those generic terms to appear with retired-offer context.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 623724cc5a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
dnm(loomPackage, retiredOfferPattern)

const sendResult = spawnSync(process.execPath, [sp("prepare-prospect-send.mjs"), legacyProspectPath, "https://www.loom.com/share/1234567890abcdef1234567890abcdef", "--approved", "--force"], {cwd: repositoryRoot, encoding: "utf8"})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Isolate the send-prep test from the live prospect workspace

Running this test invokes prepare-prospect-send.mjs with the repository as its working directory and the default outbox path. The resulting export-prospect-outbox.mjs execution scans the real relative prospects/ directory, regenerates next-message.md for every eligible prospect through ensureMessage, and overwrites prospects/outbox.html; therefore npm test can modify operator-authored prospect data outside this temporary fixture. Run the send flow against a fully isolated service workspace/output instead.

Useful? React with 👍 / 👎.

const salesPlaceholderPattern = /\badd (?:meeting link|payment link|call time)\b/i;
// Retired broad-agency offers must never project into an outbound send package.
// Mirrors the canonical retired-ask guard in export-recording-rehearsal-check.mjs.
const retiredOfferPattern = /7[-\s]day (?:site|website) revenue (?:leak|fault) (?:fix )?sprint|tangible revenue (?:leak|fault) sprint|30[-\s]day action plan|growth desk|three pages|\$\s?500\b/i;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cover all retired seven-day and 30-day variants

When recording notes contain variants such as 7-day sprint or 30-day plan, this pattern does not match and send:check can pass the retired offer. These are not hypothetical synonyms: test-sales-intake-contract.mjs explicitly classifies 7-day sprint and seven-day sprint as stale promises, while check-product-truth.mjs treats 30-day plan as stale by making action optional. Broaden the retired-ask detection while scoping it to the actual ask to avoid the previously reported whole-file false positives.

Useful? React with 👍 / 👎.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8948f8833a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +54 to +55
["send-package.md", `${packageHeader}7-Day Site Revenue Fault Sprint with a 30-day action plan. ${optOut}`],
["recording-notes.md", `# Recording Notes\n\n## Quality Notes\n\n- Clean ask: If useful, I can run a Tangible Revenue Fault Sprint with a 30-day action plan for $500.\n`]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Isolate the recording-notes case from the prior package

When the loop reaches recording-notes.md, the retired send-package.md written by the first iteration is still present, and the assertion checks only the shared rule name rather than the finding's file. Consequently, this test still passes if recording-notes.md scanning is removed or broken because the stale send package supplies the expected failure; reset the send package to safe content before the second case or assert that the finding points to recording-notes.md.

Useful? React with 👍 / 👎.

@nish3451
nish3451 merged commit 52d4da4 into main Aug 11, 2026
3 checks passed
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