diff --git a/.lane/reports/fix-operator-copy-offername-article-lane1-20260814.md b/.lane/reports/fix-operator-copy-offername-article-lane1-20260814.md new file mode 100644 index 00000000..565c3cb6 --- /dev/null +++ b/.lane/reports/fix-operator-copy-offername-article-lane1-20260814.md @@ -0,0 +1,36 @@ +# Lane 1 report — operator copy offerName article fix + +## Item + +Operator copy interpolates offerName "The Website Correction" after the word "the", producing doubled-article text ("the The Website Correction"). + +## Fix + +Branch `fix/operator-copy-offername-article-lane1-20260814` (fresh from origin/main 497d690), commit ffff72b, PR https://github.com/nish3451/tinystudio-in/pull/144 + +Dropped the redundant article at five operator copy interpolation sites: + +- scripts/draft-client-kickoff.mjs — "Thanks for approving ${config.offerName}..." +- scripts/draft-loom-recording-script.mjs — "...positions ${config.offerName} as the obvious next step." +- scripts/draft-recording-sharpness-brief.mjs — "CTA: Offer ${config.offerName} at..." +- scripts/draft-sales-call-prep.mjs — "${FOUNDER_PILOT.offerName} is exactly a..." +- scripts/draft-prospect-message.mjs — "the exact one-page scope for ${config.offerName}." + +Added regression guard in scripts/check-product-truth.mjs (part of `npm run ci`) that fails any active operator copy source interpolating the offer name directly after "the". + +## Verification (all passed) + +- node --check on all six changed files +- node scripts/check-product-truth.mjs (new guard active, exit 0) +- node scripts/test-active-operator-surfaces.mjs +- node scripts/test-sales-intake-contract.mjs +- node scripts/test-validated-service-client.mjs +- node scripts/test-client-readiness-contract.mjs +- node scripts/test-service-engine.mjs +- node scripts/test-active-offer-projection.mjs +- node scripts/check-agency-defaults.mjs + +## Notes + +- Two prior unattached attempts existed (fix/operator-copy-offername-article commit 1be28e9 covering 4 sites; fix/operator-copy-offer-article commit 5061dfd covering 5 sites + guard) — neither was ever merged. This lane re-landed the fix on current main, including the fifth site and the CI guard. +- Claim file lane-1.json `claims` updated to the six changed script paths. diff --git a/scripts/check-product-truth.mjs b/scripts/check-product-truth.mjs index d9e04374..9cfa4ecf 100644 --- a/scripts/check-product-truth.mjs +++ b/scripts/check-product-truth.mjs @@ -249,6 +249,21 @@ for (const path of activeGeneratorSources) { } } +for (const path of [ + "scripts/draft-sales-call-prep.mjs", + "scripts/draft-recording-sharpness-brief.mjs", + "scripts/draft-loom-recording-script.mjs", + "scripts/draft-client-kickoff.mjs", + "scripts/draft-prospect-message.mjs", + "scripts/lib/canonical-service-copy.mjs", + "scripts/lib/client-scaffold.mjs" +]) { + const content = existsSync(path) ? readFileSync(path, "utf8") : "" + if (/\b(?:the|The)\s*\$\{(?:config|FOUNDER_PILOT|day0)\.offerName\}/.test(content)) { + failures.push(`${path}: offer name is interpolated directly after the article 'the'`) + } +} + for (const [path, requiredPatterns] of [ [ "scripts/draft-sales-call-prep.mjs", diff --git a/scripts/draft-client-kickoff.mjs b/scripts/draft-client-kickoff.mjs index a8b51985..3f45a039 100644 --- a/scripts/draft-client-kickoff.mjs +++ b/scripts/draft-client-kickoff.mjs @@ -67,7 +67,7 @@ const approvalOwner = day0.approvalOwner; const highestLeveragePage = field(sprintPlan, "Highest-leverage page:", "choose the highest-leverage page"); const sprint = `**${day0.offerName}**\n\nIncluded: ${config.includedDeliverables.join(", ")}.`; const timingAndPrice = `- Day 0: ${day0.day0StartedAt}\n- Working-day deadline: ${day0.deadlineAt}\n- Clock rule: ${config.dayZeroRule}\n- Founder pilot ${pilotPosition} of ${FOUNDER_PILOT.capacity}: **${founderPilotPrice}**.`; -const approvalOpening = `Thanks for approving the ${config.offerName}. Day 0 is recorded and the service is paid.`; +const approvalOpening = `Thanks for approving ${config.offerName}. Day 0 is recorded and the service is paid.`; const kickoff = `# ${name} Kickoff Message diff --git a/scripts/draft-loom-recording-script.mjs b/scripts/draft-loom-recording-script.mjs index 9a55e19c..65e4f979 100644 --- a/scripts/draft-loom-recording-script.mjs +++ b/scripts/draft-loom-recording-script.mjs @@ -191,7 +191,7 @@ const script = `# ${metadata.name} Loom Recording Script ## Goal -Record a 2-3 minute cold audit that names one clear fault and positions the ${config.offerName} as the obvious next step. +Record a 2-3 minute cold audit that names one clear fault and positions ${config.offerName} as the obvious next step. ## Before Recording diff --git a/scripts/draft-prospect-message.mjs b/scripts/draft-prospect-message.mjs index 1ecf549f..7ef44e0b 100644 --- a/scripts/draft-prospect-message.mjs +++ b/scripts/draft-prospect-message.mjs @@ -118,7 +118,7 @@ if (stage === "sent" || stage.startsWith("followup-")) { body = appendEmailComplianceFooter(`Worth sending the exact ${mainPage} structure I would use for this?`); } else if (pending?.step === "day-5") { subject = `Re: Quick audit for ${name}`; - body = appendEmailComplianceFooter(`Quick bump. The main thing I would fix first is ${leakFragment}. If useful, I can send the exact one-page ${config.offerName} scope.`); + body = appendEmailComplianceFooter(`Quick bump. The main thing I would fix first is ${leakFragment}. If useful, I can send the exact one-page scope for ${config.offerName}.`); } else if (pending?.step === "day-10") { subject = `Re: Quick audit for ${name}`; body = appendEmailComplianceFooter(`Closing the loop here. I still think ${mainPage} is leaving clarity on the table. Happy to revisit if this becomes a priority.`); diff --git a/scripts/draft-recording-sharpness-brief.mjs b/scripts/draft-recording-sharpness-brief.mjs index 7132c684..060f79c2 100644 --- a/scripts/draft-recording-sharpness-brief.mjs +++ b/scripts/draft-recording-sharpness-brief.mjs @@ -219,7 +219,7 @@ Use this before recording. The job is not to sound clever. The job is to make on 4. Credibility: ${proof[0] || "use only visible proof from the live page"} 5. Solution: ${firstFix} 6. Proof: ${proof[1] || contrast} -7. CTA: Offer the ${config.offerName} at ${price} without promising revenue, rankings, ROAS, or lift. +7. CTA: Offer ${config.offerName} at ${price} without promising revenue, rankings, ROAS, or lift. ## So-What Chain diff --git a/scripts/draft-sales-call-prep.mjs b/scripts/draft-sales-call-prep.mjs index cfebf4f4..a668a31c 100644 --- a/scripts/draft-sales-call-prep.mjs +++ b/scripts/draft-sales-call-prep.mjs @@ -154,7 +154,7 @@ ${payback} ## Close -"The ${FOUNDER_PILOT.offerName} is exactly a ${founderPilotPrice()} for one highest-leverage page. Human reviewers gate the claims and client-facing work. You receive the fault map, rewrite or redesign, one implementation pass or dev-ready handoff, search-trust basics, before/after proof, Loom, measurement plan, one client revision, and 14-day implementation tracking. Day 0 starts after payment, context, and named approval and implementation owners." +"${FOUNDER_PILOT.offerName} is exactly a ${founderPilotPrice()} for one highest-leverage page. Human reviewers gate the claims and client-facing work. You receive the fault map, rewrite or redesign, one implementation pass or dev-ready handoff, search-trust basics, before/after proof, Loom, measurement plan, one client revision, and 14-day implementation tracking. Day 0 starts after payment, context, and named approval and implementation owners." ## Guardrails