fix(sales): block retired offer copy in outbound send packages - #71
Conversation
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>
There was a problem hiding this comment.
nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Warning Review limit reached
Next review available in: 7 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Comment |
There was a problem hiding this comment.
💡 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".
| if (["send-package.md", "recording-notes.md"].includes(filename) && retiredOfferPattern.test(content)) { | ||
| findings.push({ file, rule: "outbound package sells a retired offer" }); | ||
| } |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
💡 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"}) |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
💡 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".
| ["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`] |
There was a problem hiding this comment.
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 👍 / 👎.
What
The active prospect send package still sold the retired broad-agency offer.
prepare-prospect-send.mjsembedsrecording-notes.mdverbatim intosend-package.md, andrecording-notes.mdis 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.mjsonly checked opt-out language and placeholders, so a stale send package passed CI while selling the retired offer.Fix
scripts/check-outbound-send-readiness.mjsexport-recording-rehearsal-check.mjs'sRETIRED_ASK_PATTERNS) and scansend-package.mdandrecording-notes.md.outbound package sells a retired offer.scripts/test-outbound-send-readiness.mjsscripts/test-active-offer-projection.mjssend-package.mdcontains only the canonicalThe Website Correctionoffer, no guarantee outcomes, and no retired-offer phrasing.Verification
npm run ciexits 0.Closes: active prospect send package still sells the retired 7-day sprint + 30-day action plan