fix(sales): gate every runtime record/send surface against retired offer copy - #112
Conversation
…fer copy The 191 stale runtime files under prospects/ (loom-outline.md, recording-script.md, audit-brief.md, recording-sharpness-brief.md, buyer-room.md, next-message.md, outreach.md) still sell the retired 7-day sprint + 30-day action plan, and neither the send gate nor the rehearsal gate could see them or match the $1,000 founder sprint token. Extend check-outbound-send-readiness to scan every active record/send surface for the retired-offer pattern (now also 7-day sprint and founder sprint), so a stale runtime sheet fails send:check instead of silently reaching a prospect. Add the same tokens to the rehearsal RETIRED_ASK_PATTERNS. Wire proof-run prep to refresh the ask column of existing loom-links.txt rows that still name a retired offer, so npm run market:proof-run heals the sheet instead of preserving it.
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.
📝 WalkthroughWalkthroughThe PR broadens retired-offer detection across outbound documents and scoring scripts. It also refreshes matching Loom-sheet asks to the canonical prospect ask and reports the number of refreshed rows. ChangesRetired offer controls
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/export-market-proof-run.mjs`:
- Line 380: Update the retired-ask matcher in
scripts/export-market-proof-run.mjs:380-380,
scripts/export-recording-rehearsal-check.mjs:85-90,
scripts/test-active-offer-projection.mjs:15-15, and
scripts/check-outbound-send-readiness.mjs:95-95 to use token boundaries around
both the “7-day sprint” and “founder sprint” alternatives: apply \b before and
after each phrase while preserving the remaining patterns and behavior.
In `@scripts/test-outbound-send-readiness.mjs`:
- Around line 56-83: Update the retired-fixture loop around retiredFixtures so
every case starts with all outbound files reset to canonical content, preventing
prior iterations from leaving send-package.md stale. Expand the retired cases to
cover every filename in outboundFiles, including reply-package.md,
call-booked-package.md, close-package.md, audit-brief.md, buyer-room.md, and
loom-package.md, while preserving the per-case failure assertion.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b379eaa4-8f1a-42c1-84d2-aeaf38a256de
📒 Files selected for processing (5)
scripts/check-outbound-send-readiness.mjsscripts/export-market-proof-run.mjsscripts/export-recording-rehearsal-check.mjsscripts/test-active-offer-projection.mjsscripts/test-outbound-send-readiness.mjs
| // notes and Loom URL, but any ask column that still names a retired offer is | ||
| // refreshed to the canonical ask. Mirrors the retired-offer pattern in | ||
| // check-outbound-send-readiness.mjs and export-recording-rehearsal-check.mjs. | ||
| const retiredPromisePattern = /7[-\s]day (?:site|website) revenue (?:leak|fault) (?:fix )?sprint|7[-\s]day sprint|tangible revenue (?:leak|fault) sprint|30[-\s]day action plan|growth desk|three pages|founder sprint|\$\s?500\b/i; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Add token boundaries to the new generic alternatives.
/7[-\s]day sprint/ matches the 7-day sprint portion of 17-day sprint. /founder sprint/ matches cofounder sprint. In scripts/export-market-proof-run.mjs, this can replace a valid persisted ask. In the readiness checks, this can create an incorrect operator or CI failure.
Use \b7[-\s]day sprint\b and \bfounder sprint\b at every matcher site.
scripts/export-market-proof-run.mjs#L380-L380: bound the generic alternatives before migrating the ask field.scripts/export-recording-rehearsal-check.mjs#L85-L90: bound the generic alternatives before reporting rehearsal findings.scripts/test-active-offer-projection.mjs#L15-L15: use the bounded alternatives in the test helper.scripts/check-outbound-send-readiness.mjs#L95-L95: bound the generic alternatives before blocking an outbound surface.
📍 Affects 4 files
scripts/export-market-proof-run.mjs#L380-L380(this comment)scripts/export-recording-rehearsal-check.mjs#L85-L90scripts/test-active-offer-projection.mjs#L15-L15scripts/check-outbound-send-readiness.mjs#L95-L95
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/export-market-proof-run.mjs` at line 380, Update the retired-ask
matcher in scripts/export-market-proof-run.mjs:380-380,
scripts/export-recording-rehearsal-check.mjs:85-90,
scripts/test-active-offer-projection.mjs:15-15, and
scripts/check-outbound-send-readiness.mjs:95-95 to use token boundaries around
both the “7-day sprint” and “founder sprint” alternatives: apply \b before and
after each phrase while preserving the remaining patterns and behavior.
| const retiredFixtures = [ | ||
| ["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`] | ||
| ]) { | ||
| ["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`], | ||
| ["loom-outline.md", `# Loom Outline\n\n7. Sprint pitch: 7-Day Site Revenue Fault Sprint with a 30-day action plan\n`], | ||
| ["recording-script.md", `# Recording Script\n\n## Talk Track\n\nIf useful, I can run a 7-day sprint where I map this fault for $1,000 founder sprint.\n`], | ||
| ["next-message.md", `${packageHeader}If useful, I can run a 7-day sprint where I map this leak and give you a 30-day action plan. ${optOut}`], | ||
| ["recording-sharpness-brief.md", `# Sharpness Brief\n\n## Positioning Angle\n\nOffer the The Website Correction at $1,000 founder sprint.\n`], | ||
| ["outreach.md", `# Outreach\n\n## First Message\n\nIf useful, I can run a 7-day sprint where I map this fault and give you a 30-day action plan. ${optOut}`] | ||
| ] | ||
| for (const [file, content] of retiredFixtures) { | ||
| writeFileSync(join(prospect, file), content) | ||
| result = run() | ||
| assert.notEqual(result.status, 0, `expected retired-offer failure for ${file}`) | ||
| assert(output(result).findings.some(finding => finding.rule === "outbound package sells a retired offer")) | ||
| } | ||
|
|
||
| writeFileSync(join(prospect, "send-package.md"), `${packageHeader}The Website Correction, one highest-leverage page, 14-day implementation tracking. ${optOut}`) | ||
| writeFileSync(join(prospect, "recording-notes.md"), `# Recording Notes\n\n## Quality Notes\n\n- Clean ask: If useful, I can run a human-reviewed The Website Correction on this one highest-leverage page with a measurement plan.\n`) | ||
| // Canonical copy on every surface must pass the retired-offer rule. | ||
| for (const [file, content] of [ | ||
| ["send-package.md", `${packageHeader}The Website Correction, one highest-leverage page, 14-day implementation tracking. ${optOut}`], | ||
| ["recording-notes.md", `# Recording Notes\n\n## Quality Notes\n\n- Clean ask: If useful, I can run a human-reviewed The Website Correction on this one highest-leverage page with a measurement plan.\n`], | ||
| ["loom-outline.md", `# Loom Outline\n\n7. Ask: If useful, I can run a human-reviewed The Website Correction on this one highest-leverage page with 14-day implementation tracking.\n`], | ||
| ["recording-script.md", `# Recording Script\n\n## Talk Track\n\nIf useful, I can run a human-reviewed The Website Correction on this one highest-leverage page.\n`], | ||
| ["next-message.md", `${packageHeader}If useful, I can run a human-reviewed The Website Correction on this one highest-leverage page. ${optOut}`], | ||
| ["recording-sharpness-brief.md", `# Sharpness Brief\n\n## Positioning Angle\n\nThe Website Correction at the $1,000 founder pilot.\n`], | ||
| ["outreach.md", `# Outreach\n\n## First Message\n\nIf useful, I can run a human-reviewed The Website Correction. ${optOut}`] | ||
| ]) { | ||
| writeFileSync(join(prospect, file), content) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Isolate and complete each outbound fixture case.
After the first iteration, send-package.md remains stale. Each later check can fail because of that file instead of the current fixture. The fixture list also omits reply-package.md, call-booked-package.md, close-package.md, audit-brief.md, buyer-room.md, and loom-package.md, although the readiness checker scans them.
Reset all outbound fixtures to canonical content before each retired case. Add a retired case for every filename in outboundFiles.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/test-outbound-send-readiness.mjs` around lines 56 - 83, Update the
retired-fixture loop around retiredFixtures so every case starts with all
outbound files reset to canonical content, preventing prior iterations from
leaving send-package.md stale. Expand the retired cases to cover every filename
in outboundFiles, including reply-package.md, call-booked-package.md,
close-package.md, audit-brief.md, buyer-room.md, and loom-package.md, while
preserving the per-case failure assertion.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4391319592
ℹ️ 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)) { | ||
| if (retiredOfferPattern.test(content)) { |
There was a problem hiding this comment.
Restrict retired-offer matching to actual offer sections
When a prospect's own pricing or page structure is copied into loom-outline.md, recording-sharpness-brief.md, or recording-script.md, this whole-file check treats descriptive phrases such as “three pages” or “$500” as though TinyStudio were selling the retired offer. These recording surfaces intentionally contain observed page cues and fault evidence, so an unrelated prospect statement can now fail send:check and the market-parity gate; inspect only the ask/CTA portions or require enough context to identify the retired offer.
Useful? React with 👍 / 👎.
| for (const [file, content] of retiredFixtures) { | ||
| writeFileSync(join(prospect, file), content) | ||
| result = run() | ||
| assert.notEqual(result.status, 0, `expected retired-offer failure for ${file}`) | ||
| assert(output(result).findings.some(finding => finding.rule === "outbound package sells a retired offer")) |
There was a problem hiding this comment.
Isolate each retired-surface fixture before running the gate
After the first iteration writes a retired send-package.md, that file remains in the fixture for every later iteration, and the assertion only checks that some retired-offer finding exists. Consequently, the test still passes if the checker completely ignores recording-notes.md, loom-outline.md, recording-script.md, and every other newly listed surface; remove or canonicalize the previous fixture before each run, or assert that the finding names the file under test.
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: 48ebb428f8
ℹ️ 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".
| .map((line) => line.trim()) | ||
| .filter((line) => line && !line.startsWith("#")) | ||
| .map((line) => { | ||
| if (!line.includes("|")) return line; |
There was a problem hiding this comment.
Refresh comma-delimited proof rows too
When an existing Loom sheet row uses the supported comma-delimited format, this early return skips retired-offer replacement even though parseLoomSheetLine, update-market-proof-looms.mjs, and prepare-prospect-batch-send.mjs all accept comma-separated rows. Regenerating the proof run therefore leaves the stale ask in the sheet that operators are instructed to record from; parse using the same delimiter selection as the consumers before inspecting and replacing the ask column.
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: 1b3721afec
ℹ️ 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".
| "reply-package.md", "call-booked-package.md", "close-package.md", | ||
| "loom-outline.md", "recording-script.md", "recording-sharpness-brief.md", | ||
| "audit-brief.md", "buyer-room.md", "loom-package.md" |
There was a problem hiding this comment.
Include sales-call prep in the retired-offer scan
When a legacy sales-call-prep.md still contains the retired sprint, send:check passes because this active sales-call close packet is omitted from outboundFiles, even though draft-sales-call-prep.mjs emits it for operators and check-outbound-claim-safety.mjs classifies it as outbound. Include this filename so the new “every active record/send surface” gate also blocks stale offer copy from being used on calls.
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: 9eba6059bb
ℹ️ 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".
|
|
||
| const RETIRED_ASK_PATTERNS = [ | ||
| /7[-\s]day (?:site|website) revenue (?:leak|fault) (?:fix )?sprint/i, | ||
| /7[-\s]day sprint/i, |
There was a problem hiding this comment.
Check the spoken script for retired offers
When loom-outline.md has a canonical ask but the generated or hand-edited recording-script.md still says “founder sprint” or “7-day sprint,” prospect:rehearsal can report the prospect ready: scoreProspect applies retiredOfferAsk only to the ask extracted from the outline, while the script's talkTrack is checked only for unsupported claims. Apply these retired-offer patterns to the talk track as well so the recording gate stops operators before they record stale spoken copy rather than relying on the later send-readiness check.
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: cde0dbb400
ℹ️ 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".
| const outboundFiles = new Set([ | ||
| "next-message.md", "send-package.md", "recording-notes.md", "outreach.md", | ||
| "reply-package.md", "call-booked-package.md", "close-package.md", | ||
| "loom-outline.md", "recording-script.md", "recording-sharpness-brief.md", | ||
| "audit-brief.md", "buyer-room.md", "loom-package.md" |
There was a problem hiding this comment.
Include the Loom sheet in the retired-offer gate
When an existing prospects/loom-links.txt contains a retired ask and the operator starts the recording workflow without first rerunning market:proof-run, the export-only cleanup never executes. The proof-run instructions identify this sheet as the recording source, but this allowlist excludes it, so both send:check and the parity gate can pass while the operator records stale offer copy; scan the sheet's ask column here as well.
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: 41dbe9f17e
ℹ️ 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".
| const outboundFiles = new Set([ | ||
| "next-message.md", "send-package.md", "recording-notes.md", "outreach.md", | ||
| "reply-package.md", "call-booked-package.md", "close-package.md", | ||
| "loom-outline.md", "recording-script.md", "recording-sharpness-brief.md", | ||
| "audit-brief.md", "buyer-room.md", "loom-package.md" |
There was a problem hiding this comment.
Scan the generated teleprompter and outbox
When prospects/recording-teleprompter.html or prospects/outbox.html predates source normalization, this filename allowlist ignores the stale generated copy, so send:check passes even if those pages still contain a retired offer. This is directly user-facing because start-growth-mission.mjs opens the existing teleprompter for --view=record and the existing outbox for --view=send without regenerating either page; include these generated record/send surfaces in the retired-offer gate.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37c1004edf
ℹ️ 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".
| // or any runtime sheet that feeds it (loom outlines, recording scripts, | ||
| // sharpness briefs, audit briefs, buyer rooms). Mirrors the canonical | ||
| // retired-ask guard in export-recording-rehearsal-check.mjs. | ||
| const retiredOfferPattern = /7[-\s]day (?:site|website) revenue (?:leak|fault) (?:fix )?sprint|7[-\s]day sprint|tangible revenue (?:leak|fault) sprint|30[-\s]day action plan|growth desk|three pages|founder sprint|\$\s?500\b/i; |
There was a problem hiding this comment.
Recognize worded seven-day promises
When a legacy runtime surface says “seven-day sprint” instead of “7-day sprint,” this new gate passes it unchanged because the added generic branch only accepts the numeral. The repository already classifies that spelling, plus phrases such as “fix in seven days,” as stale delivery promises in scripts/test-sales-intake-contract.mjs; use the same retired-promise variants here so send:check cannot approve those runtime files.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f5900cda5a
ℹ️ 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)) { | ||
| if (retiredOfferPattern.test(content)) { |
There was a problem hiding this comment.
Exclude inactive prospects from the expanded scan
When a prospect has been marked won, lost, or paused but a historical loom-outline.md, recording-script.md, or other newly scanned file retains retired copy, this unconditional check still fails send:check and therefore the market-parity gate. The recording rehearsal, teleprompter, proof-run, and batch-send workflows explicitly exclude those stages, so these are no longer active record/send surfaces; filter prospect folders by pipeline status before applying the expanded scan.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4189e43484
ℹ️ 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".
| /30[-\s]day action plan/i, | ||
| /growth desk/i, | ||
| /three pages/i, | ||
| /founder sprint/i, |
There was a problem hiding this comment.
Check the sharpness brief for retired offers
When the outline contains a canonical ask but recording-sharpness-brief.md still says “founder sprint,” the rehearsal can report the prospect ready because scoreProspect reads brief but applies retiredOfferAsk only to the outline-derived ask. export-recording-teleprompter.mjs then renders that unchecked brief directly in the recording view, so the operator can still record from stale offer copy; include the brief in this retired-offer check.
Useful? React with 👍 / 👎.
…le with main after PRs #135/#104/#99/#112/#100/#105) The PR #130 branch had already been reconciled with origin/main through c617364 (PRs #131 + #133/#134/#132/#116). Since then origin/main moved to d4f3ef4 with six more merges (#135 #104 #99 #112 #100 #105). Pull them in so PR #130 can be reviewed against current main without weakening the capture/rollback/reverification implementation or the PR #131 fail-closed missing-secret gate. The merge resolved cleanly: - PR #130 capture/rollback logic (publish-public-site.mjs canonical_deployment, rollbackTo, restored identity re-verify, accept-again) is intact. - PR #130 test file (scripts/test-pages-release.mjs) is intact and wired into the npm ci/test scripts. - PR #131 fail-loud missing-secret workflow step in .github/workflows/deploy-public-site.yml is preserved byte-for-byte. - The new origin/main changes touch operator surfaces and the deploy bundle prep; none of them modify the publish-public-site.mjs rollback contract or the Pages token gate, so there were no conflict markers.
What
The open item: Active prospect send package still sells the retired 7-day sprint + 30-day action plan in 191 runtime files. PR #71 (52d4da4) covered only
send-package.md+recording-notes.md; the ~191 stale runtime sheets (loom-outline.md,recording-script.md,audit-brief.md,recording-sharpness-brief.md,buyer-room.md,next-message.md,outreach.md) were invisible to both the send gate and the rehearsal gate, and neither pattern list matched the residual$1,000 founder sprinttoken (current offer is$1,000 founder pilot).Changes
check-outbound-send-readiness.mjs(send:check, in CI): scan every active record/send surface for retired-offer copy, not just send/recording notes. Pattern now also matches generic7-day sprintandfounder sprint(alongside the existing 7-Day Site Revenue Fault Sprint / 30-day action plan / growth desk / three pages / $500).export-recording-rehearsal-check.mjs: same two tokens added toRETIRED_ASK_PATTERNSso the rehearsal Clean-ask gate flagsfounder sprintruntime briefs too.export-market-proof-run.mjs(npm run market:proof-run): refresh the ask column of existingprospects/loom-links.txtrows that still name a retired offer, replacing it with the canonical Website Correction ask (fault/impact/fix notes and Loom URL preserved). This wires regeneration from canonical copy into proof-run prep - the item's verify step now heals the sheet instead of preserving the stale ask.test-outbound-send-readiness.mjsfixtures now cover every surface (loom-outline, recording-script with$1,000 founder sprint, next-message, sharpness brief, outreach) asserting retired copy fails and canonical copy passes;test-active-offer-projection.mjspattern list extended with the new tokens.Verification
node scripts/test-outbound-send-readiness.mjs,test-active-offer-projection.mjs,test-sales-intake-contract.mjs,test-client-readiness-contract.mjsall pass.npm run cichain green exceptcheck-retention-automation.mjs, which fails identically on clean base (VPS-global automation file points at the product repo path, not this worktree - pre-existing environment issue, unrelated).market:proof-runon a staleloom-links.txt: stale ask row rewritten to canonical ask (refreshedAsks: 1), canonical rows untouched.Runtime
prospects/data is gitignored and lives in the product root, so the 191 stale sheets are healed by runningnpm run market:proof-run/npm run send:normalizethere; this change makes the gate fail loud until they are.Summary by CodeRabbit
Bug Fixes
Tests