Coaching V1 post-lesson survey program spec
Summary
The V1 post-lesson survey program is settled across all three domains (2026-05-22-coaching-nps-program-v1-cadence-accepted): two instruments, the count-based cadence, the Delivery-local capture surface, the External Actions Queue send, and the trailing-8-week coach aggregate. Delivery noted that the one piece sequenced after the rest is the user-facing content. This memo delivers it: the message copy and one-tap form content for both instruments, plus the coach_quality_score formula and the trigger configuration values, so Delivery has everything it needs to finish the V1 build.
Coaching owns this content as program sponsor. Three principles run through it. First, the copy is written for the common case, a guardian receiving the message about a minor student, with an adult-participant variant for adults who hold their own Participant. Second, every field the program captures is quantitative: each response is a numeric rating and each optional follow-up is a structured single-select reason code, so V1 captures no free text and all survey output is countable and trendable. Third, the spec is coaching-vertical-agnostic: the customer-facing brand is a {brand_name} token resolved per deployment, and the copy and reason categories carry no vertical-specific terms, so the program is reusable across coaching verticals.
Survey copy: CSAT
CSAT fires after attended lessons 1, 9, 17, and onward. It rates the lesson, and through the lesson the coach who delivered it. V1 uses one CSAT message for every lesson, lesson 1 included; there is no separate first-lesson variant.
Message, guardian variant:
{brand_name}: Hi {guardian_first_name}! How did {student_first_name}'s lesson go today? Tap to rate it, takes about 10 seconds: {link}
Message, adult-participant variant:
{brand_name}: Hi {first_name}! How did your lesson go today? Tap to rate it, takes about 10 seconds: {link}
One-tap form:
- Heading:
{brand_name} - Question, guardian variant: "How was {student_first_name}'s lesson with Coach {coach_first_name} today?" Adult variant: "How was your lesson with Coach {coach_first_name} today?"
- Rating control: five tappable options, 1 to 5, left-anchored "Not great" and right-anchored "Loved it". One tap records the rating.
- Reason follow-up, shown only when the rating is 1, 2, or 3: a single-select list, "What would have made it better?" Options: "Coaching and communication", "Lesson difficulty or pace", "{student_first_name}'s enjoyment and engagement" (adult variant: "My enjoyment and engagement"), "Scheduling or timing", "Facility or equipment", "Other". The reason is optional and skippable; a rating of 4 or 5 goes straight to the confirmation.
- Confirmation screen: "Thanks, {guardian_first_name}. This helps us give {student_first_name} the best coaching." Adult variant substitutes second-person phrasing.
Survey copy: NPS
NPS fires after attended lessons 5, 21, 37, and onward. It rates the {brand_name} relationship. It deliberately does not mention the coach: NPS is a relationship-level signal, and naming a coach would invite a coach rating, which is the conflation the two-instrument design avoids.
Message, guardian variant:
{brand_name}: Hi {guardian_first_name}, {student_first_name} has been taking lessons with us for a little while now. One quick question, about 15 seconds: {link}
Message, adult-participant variant:
{brand_name}: Hi {first_name}, you have been taking lessons with us for a little while now. One quick question, about 15 seconds: {link}
One-tap form:
- Heading:
{brand_name} - Question: "How likely are you to recommend {brand_name} to a friend or family member?"
- Rating control: eleven tappable options, 0 to 10, left-anchored "Not at all likely" and right-anchored "Extremely likely". One tap records the score.
- Reason follow-up, shown after any score: a single-select list, "What most affected your score?" Options: "Coaching quality", "Scheduling and availability", "Price and value", "Facility or equipment", "{student_first_name}'s progress" (adult variant: "My progress"), "Other". The reason is optional and skippable.
- Confirmation screen: "Thank you, {guardian_first_name}. We really appreciate it." Adult variant substitutes the name token.
One-tap form behavior
The form is one surface for both instruments, parameterized by instrument type.
- The link carries a signed binding to the rated lesson and the delivering coach, per Delivery's earlier design, so the form needs no login and the response attributes itself with no user input.
- Mobile-first. The rating options are large tap targets; one tap records the rating and, where applicable, reveals the single-select reason list and a submit control.
- The reason follow-up is always optional and never blocks submission. A respondent can finish on the single rating tap.
- The program captures no free text in V1. Every captured field is structured: a numeric rating and an optional categorical reason code. This keeps all survey output quantitative and countable, and it simplifies the build. A free-text field is a straightforward V2 addition if qualitative depth is wanted later.
- The reason codes are captured as structured data for operator and program analytics. They do not feed
coach_quality_scoreorcustomer_satisfaction_of_coach; those metrics are computed from the rating only. The reason codes are a separate, countable dataset (a breakdown by category), not a metric input in V1. - After submit, the confirmation screen ends the flow. No account, no upsell, no further questions in V1.
- If the link is opened again after a response is recorded, the form shows the confirmation screen rather than accepting a second submission. Delivery's per-lesson, per-trigger dedup covers the send side; this covers the form side.
- V1 is English only. Localization is a future enhancement, noted so it is a deliberate V1 boundary and not an oversight.
The coach_quality_score formula
coach_quality_score is computed only from the CSAT rating. The formula has three steps.
Per-response normalization. Each CSAT response is an integer 1 to 5. It normalizes to a rate
r = (raw - 1) / 4, so 1 maps to 0.00, 2 to 0.25, 3 to 0.50, 4 to 0.75, and 5 to 1.00. The capture surface stores the raw response andrside by side, as Delivery proposed.Coach-week aggregate. For each
(tenant_id, coach_id, week), over the trailing 8 weeks of CSAT responses attributed to that coach:response_countis the number of responses andmean_rateis the arithmetic mean ofracross them. NPS responses are excluded and customer identity is stripped, both inside Delivery's projection. The CSAT reason codes are not part of this aggregate.The score.
coach_quality_score = mean_rate, a rate in the range 0 to 1 where higher is better, emitted weekly per coach. Whenresponse_count < 5the score is not emitted; see the null note below.
Worked example: a coach whose trailing-8-week CSAT responses are 5, 4, 5, 3, 5, 4, 5 has 7 responses, normalizing to 1.00, 0.75, 1.00, 0.50, 1.00, 0.75, 1.00, a mean_rate of about 0.857, so coach_quality_score is about 0.857.
V1 keeps the formula deliberately plain: a flat mean over the window, with no recency weighting and no per-response weighting. The org-market rollup uses the registry's existing weighted_mean_by_customer_count rule and is unchanged. When Platform wires the compute, this formula is what coach_quality_score's registry entry should declare, per the registry note that the metric declares its formula when present.
Null note: the < 5 guard means many coach-weeks will legitimately carry no score, which is correct. coach_quality_score's allowed_null_reasons in the registry currently lists only null:not_applicable and null:upstream_unavailable. An under-threshold coach-week is an insufficient-data case, so wiring the compute will likely need null:insufficient_data added to that metric's allowed_null_reasons. This is flagged to Platform below; it is not a V1 blocker.
Trigger configuration values
These restate the settled cadence as the configuration Delivery parameterizes into the trigger. They are not new; they are collected here so the spec is self-contained.
- Lesson counter: a per-participant positional index over attended lessons, incremented only on
lesson.attended. The first attended lesson is index 1. - CSAT fires at lesson index n where n = 1 + 8k for integer k >= 0: lessons 1, 9, 17, 25, and onward.
- NPS fires at lesson index n where n = 5 + 16k for integer k >= 0: lessons 5, 21, 37, 53, and onward.
- The two cadences never coincide, so no precedence rule is needed.
- Reason-follow-up display rule (form config, not the trigger): the CSAT reason list shows on ratings of 1, 2, or 3; the NPS reason list shows on every score.
Open items and asks
To Delivery. Confirm the send composer can supply the tokens used above: the per-record personalization tokens {guardian_first_name}, {student_first_name}, {coach_first_name}, and {first_name} for the adult variant; the routed_through_guardian flag that selects between the guardian and adult variants; and {brand_name}, a per-deployment brand string rather than a per-record token. Confirm the one-tap link can carry the signed lesson-and-coach binding the form relies on. Confirm the capture surface can store the structured reason code alongside the rating. Flag anything in the copy or form content that is not buildable as specified. With this spec delivered, the user-facing-content piece Delivery identified as the last item sequenced after the program spec is unblocked.
To Platform. A small registry heads-up, not a V1 blocker: when coach_quality_score's compute is wired, the < 5 minimum-N guard will produce insufficient-data nulls, and the metric's allowed_null_reasons currently allows only null:not_applicable and null:upstream_unavailable. Adding null:insufficient_data will likely be needed. Coaching raises it now so it is not a surprise at wiring time.
From Coaching. Coaching owns the copy, the reason categories, and the formula as delivered here, and will iterate the copy and categories with Delivery if response-rate testing or operator feedback surfaces issues. The trigger configuration values are final per 2026-05-22-coaching-nps-program-v1-cadence-accepted.
References
- Coaching's cadence acceptance:
2026-05-22-coaching-nps-program-v1-cadence-accepted - Delivery's cadence counter-proposal:
2026-05-22-delivery-nps-program-v1-cadence-counter-proposal - Platform's period_attribution confirmation:
2026-05-22-platform-nps-program-v1-period-attribution-confirmation - Coaching's V1 instruments and cadence memo:
2026-05-22-coaching-nps-program-v1-instruments-and-cadence - Thread root:
2026-05-19-platform-mart-100-percent-deployment-per-domain-asks - Registry entries for
coach_quality_scoreandcustomer_satisfaction_of_coach:platform/lib/mart/registry.ts - External Actions Queue contract:
contracts/external-actions/README.md, §4.3; ADR-0011