Stevan's replay review, 2026-09-27
Recorded from your listen to the strong onboarding call 3339895706 on the deployed dashboard (your session 1d160d96, policy v4, played at 1.00x). Three points, each answered in the same shape as FEEDBACK-2026-09-25.md: your words, what we found, what changes. The engineering side is docs/architecture/proposal-m1b-live-plan.md.
Four investigations ran on the live data and the code after your review: the replay forensics of your session, the code path, the reference copilot and the live-audio path, and the plan's product semantics. Every number below comes from them. Where they disagreed, the proposal says which figure we kept and why.
Line numbers below are the current transcript's (transcript_rev 1); the M1b re-import renumbers them and the proposal carries the citations over. Two independent reviews of this document and the proposal were applied on 2026-09-27 (proposal §10).
Each finding carries one of four tags: bug (the code does something it should not), design choice (it does what G specified, and the spec needs changing), policy gap (the words or rules in the policy are missing something), milestone boundary (planned for a later milestone).
Which session, and where you stopped. The forensics found one session under your email. The first report saw decisions up to line 69 (call time 06:43), a later one up to line 107 (08:56), so you seem to have played on after a pause. Everything you said concerns the first seven minutes, and every decision you saw was a cache hit, so what you watched is exactly what run 49e3e48f produced. That matters for point 2: three other runs of the same call differ in small ways (below).
Verbatim
(1) The transcription doesn't show up as the person is speaking. Instead, it only shows up after they complete their turn ... this co-pilot is meant to be a live feedback system. And the Jev system should be really responding almost as the user is speaking. So it's by paragraph or sentence rather than turn ... that's what the GitHub did. It was much more live than our version ... they may have mentioned two or three things that are worth addressing in a particular turn.
(2) [A Saudi riyal sale like this one:] we know most likely this is going to be a salary payment back home. The plan for the call kind of skipped to understand the transfer. It repeated "the client may be somewhere we can't serve". That was twice ... two ticks, even though it's different timestamps. "Check we can serve them" ... feels like a dud question ... if we believe we can serve them, we don't have to say that explicitly on a call, which might mean that this point would never get ticked. So I actually don't know what "check we can serve them" should be for these calls. A few of these points would never get touched on. Like fund from your own account ... who holds the money? If someone's repatriating funds from home ... What if you know the answer and you don't have to ask it ... Is it okay that some of these get skipped? ... It's not a checklist, but it's there to help you. Maybe that's the positioning ... when I share it with a team, they'll be thinking ... are you telling me how to do my job ... these calls aren't necessarily scripted. We just touch on the points that are applicable.
(3) The suggestions of what to say, they don't really show up ... they also kind of disappear a little bit ... there was a suggestion of "say this" and then it disappeared before I could fully read it.
1. "It only shows up after they complete their turn"
What we found
The transcript really does wait for the end of the turn, and this call has very long turns. A line is drawn only once the clock passes the line's end time (web/src/transcript.ts:209-212), and Jev is asked at the same moment (web/src/clock.ts:429). Most lines are short, so most of the time that is invisible. The long ones are not.
| Measure, call 3339895706 | Value |
|---|---|
| Lines in the transcript | 122 (96 turns, 26 backchannels such as "Yeah") |
| Length of a line: median / 90th percentile / longest | 1.0 s / 14.4 s / 44.5 s |
| Lines of 15 s or more | 11, holding 309.6 of the 619.2 s of speech (45% of all words) |
| Wait from a word being spoken to it appearing on screen, averaged over words | 9.1 s |
| The longest client turn (line 8, "I'd like to send some money over...") | 44.5 s, 112 words, 5 separate things said |
| Jev's own thinking time once asked | 0.3 s (median 294-312 ms) |
The five longest client turns carried 19 distinct asks or facts (5, 4, 4, 3, 3), and each turn got exactly one decision. That is the "two or three things worth addressing" you noticed. Two of them were lost outright: the Canada corridor and "about 5,000 Canadian every month" (line 33) never became chips, because the plan holds one currency pair and one amount; and "I get paid on the fifteenth" (line 71) never set the purpose to salary (point 2).
Tag: design choice, in two parts. M1 chose honest timing (text appears when it is finished, never before it was said) and it took the Aircall recording's turns as they come: the source itself has fragments up to 41.4 s and 122 words. Our stitcher only splits a turn above 120 words (src/ingest/stitch.ts:59), so those long turns pass through whole.
The reference was not sentence-level either. It asked Jev once per finished utterance, fired when that utterance's end time passed (reference/jev-sales-copilot/static/index.html:483, engine.py:203-213). Three things made it feel live:
| What the reference did | Number |
|---|---|
| Short, mostly hand-written lines | median 17-42 words; its one real recording had a median of 9.9 s per line, longest 28.1 s |
| Replay never waited long, even at 1x | silences capped at 6 s (server.py:27); the demo ran at 4x and 20x |
| Live-mic mode showed words as they were spoken | interim words on screen; Jev still saw only finished lines |
| Decisions per minute | about 5, against our 9.9 on this call |
So we already decide twice as often as the reference. What we lack is the bound on the worst case (a 45 s wait during a long turn) and the sense of text arriving as it is spoken.
Jev's speed is not the constraint. Over 5,655 live requests the model answers in 304 ms (median) and 413 ms (95th percentile), flat against request size. The 1.36 s figure in earlier reports was the 95th percentile of one old run.
What changes
- Transcript words appear as they are spoken (replay). The browser reveals each line's text word by word between the line's start and end, at the recording's own pace (this call runs at 3.0 words a second). No Jev cost. The timing inside a line is estimated, because Aircall gives no per-word times: words are spread evenly inside each fragment, and only the fragment boundaries are real. Short lines are exact enough; inside a long fragment (this call's run to 41 s) a pause shifts the words after it by the pause's length, so the reveal is an animation of an estimate, not a measurement. Real word times arrive with nova-3 (uploads now, live in M3), and the same behaviour carries over.
- Jev is asked at sentence ends inside long turns (replay). A long turn is split at a sentence end once at least 6 words and 5 s have passed since the last decision, and forced at 12 s. Measured on the real lines of this call:
| Today | Sentence-level | |
|---|---|---|
| Decision points | 96 | 133 |
| Longest wait between decisions | 45.6 s | 13.5 s |
| 90th-percentile wait | 16.0 s | 10.4 s |
| Jev cost per call (this call) | $0.034 | about $0.047 |
Deciding on every sentence would be 27.8 decisions a minute and too costly; the 5 s / 12 s rule is the middle. Chips, ticks and cautions then land within a sentence or two of the words. The customer-success call goes from $0.038 to about $0.048. The pre-judged questions of point 3 (rule 6) add about 1,200 tokens to each client-part request, so the two strong calls land at about $0.050-0.053, at or just over the $0.05 per call gate the eval enforces (scripts/lib/eval-l6.ts:25); the gate is yours to re-set (decision 16). The gap figures are measured on the same evenly spread word times as point 1, so a pause inside a long fragment moves them a little.
3. What moves at a sentence end, and what still waits for the turn. Ticks, chips and cautions are feedback on what was just said and will move at sentence ends. Whether the card itself may switch mid-turn is your decision (below).
4. Live audio is M3 (milestone boundary). Streaming transcription (nova-3 on Workers AI) gives interim words and finished sentences every 4-10 s with a speaker per word. Realistic live feel: transcript words about 1 s behind speech; a tick or chip 1-2 s after each sentence ends. Two costs to know now: it is $0.552 an hour, which is $0.090 for this 587 s call on top of the engine's $0.05, so a live call costs about $0.14 all in; and the free allowance covers about 12 minutes of live audio a day only if nothing else uses it, so live needs the paid Workers plan. Whether Aircall exposes a live audio stream (or one leg per party) is still unverified, and one review named Aircall's own real-time transcription webhook as an alternative we have not checked. A one-day transport spike belongs before M3 is planned; nothing in M1b depends on it.
Your decision (1a): the cadence rule.
| Option | Decisions on this call | Worst wait | Cost per call, before pre-judge | Note |
|---|---|---|---|---|
| A. Sentence end after 6 words and 5 s, forced at 12 s (recommended) | 133 | 13.5 s | $0.047 | Bounded worst case, fewest extra decisions |
| B. Split every 25 words | 152 | 12.4 s | $0.050 | Simplest code, but at the cost gate |
| C. Every sentence | about 270 | a few seconds | about $0.09 | Too dense to read, too costly |
Your decision (1b): may the card switch mid-turn? G's first cadence rule says the card moves only when a client turn ends, never while the rep is talking.
| Option | What you see | Recommendation |
|---|---|---|
| A. Ticks, chips, cautions and new points on the open card move at sentence ends; the card switches only at the end of the speaker's turn (recommended) | Live feedback within a sentence; the headline stays put until the client finishes | Keeps the "one thing to look at" promise |
| B. Everything, the card included, may move at a sentence end | Most live; a 45 s turn can switch the card twice | More to read while listening |
2. The call plan
2a. "We know most likely this is going to be a salary payment back home"
What we found. The purpose of the transfer was never captured, in any of the four runs of this call. Two reasons:
- Policy gap. The trigger for the transfer-purpose question needs a word like salary, wages or pension (
policy/src/plan-onboarding.json:176). "I get paid on the fifteenth" (line 71) and "pay home" (line 88) do not match. So "Understand the transfer" could never be done, because its done rule needs purpose, amount and frequency, and only the last two were filled. - Design choice, now wrong. Every session starts empty (
src/engine/state.ts:17-38). The sign-up wizard already records purpose, currencies, expected volume, frequency and country (docs/research/ct-domain-brief.md§1.2), and the call row stores the CRM keypd_ct_id, but nothing reads it. This sample call's key is empty, so today there is nothing to join.
What changes.
- Facts known before the call are loaded as chips at the start, each with its source. "From sign-up" is for the CT join, which is M2 work; this sample call's CRM key is empty, so for the demo the values (personal client, lives in Saudi Arabia, SAR to NZD, salary, monthly, plus the amount and the documents status) are typed in by hand from what the call itself establishes, and the chip says "Seeded for the demo", never "From sign-up". One sample call (3485591407,
pd_ct_id109829) already carries a real key for the join. Two things to know about that join: the wizard records source and destination countries, not where the client lives (docs/research/ct-domain-brief.md§1.2), so residency comes from the KYC address; and a sign-up value is a starting point, not ground truth: a confident different value on the call replaces it and the chip reads "updated". A question whose answer is already known is never shown. Values come only from closed lists (a country id, an ISO currency code, a purpose from the list), never free text, so nothing personal leaks into the replay. - A segment prior: a client selling SAR who lives in Saudi Arabia is most likely sending salary home. It ranks which suggestions are likely to matter (a test transfer first, first-payment delays from Saudi banks, address worries). It never becomes a chip on its own; the chip needs sign-up data or the client's words.
- The trigger gains "paid", "payday", "pay home", "earn" and "income".
2b. "It repeated 'the client may be somewhere we can't serve'. That was twice"
What we found: a bug, not a re-plan. The purpose locked once (line 1, confidence 0.92) and never changed, so no template switch happened. The two ticks are two different plan rows with the same title:
| Row | Raised | Done | What closed it |
|---|---|---|---|
concern:jurisdiction:54 |
05:08, "a little bit worried about that just in terms of being a tax resident" | 05:26 | the 3-word fragment "Sure. Well, I" (line 56) was read as the client accepting |
concern:jurisdiction:58 |
05:27, "both. I'm just more hesitant just because" | 06:04 | the topic moved on |
One client sentence ("Sure. Well, I can give both. I'm just more hesitant...") was cut into four lines by the rep's interjections, so the concern closed and reopened 1.7 s apart. The engine treats a reopen as a new row (src/engine/plan.ts:449 builds the id from the line it started on), and a concern clears on any client line with an accepting signal, however short (src/engine/concern.ts:120).
There is a second problem underneath. The client's worry was tax residency and privacy around giving a New Zealand address. The policy has no such concern type, so the classifier picked the nearest one, jurisdiction, whose headline is "Client may be somewhere we can't serve" (policy/src/playbook-onboarding.json:2056). Neither row ever showed a suggestion, only the title and "Listening". In your run the topic therefore appeared three times: those two rows plus the template's own "Check we can serve them".
What changes.
- A concern of the same type raised again within 60 s of call time reopens the same row ("raised again 05:27") instead of adding one. The window is in seconds, not decisions, so the sentence-level cadence does not shrink it.
- A concern cannot close on a client line under 4 words, whatever Jev scores it: line 56 scored "accepting" at 0.71-0.77 in every run of this call. Whether a line ends mid-sentence is not used, because the engine cannot know a turn is the last of its run until the next one arrives. Measured on this call's recorded answers, the guard leaves one row: raised at 05:08, raised again at 05:27 (the same row, since it never closed), done at 06:04 on "It is. It's very" (4 words), as today.
- The jurisdiction concern cannot open while the client's country is known and on the served list. The policy has no such list today, so it starts empty and the gate does nothing until you or the partners supply one; "known" alone must not silence it, or the "we can't serve you" exit in 2c is lost.
- A new document situation for this worry, drafted for your red pen: headline "Will this address tie me to that country?", hint "One address is enough; don't push a second one.", line "We only need one proof of address, and your {country} one is fine." ({country} is filled from the residency slot, as the other country lines are.) The line is marked [VERIFY]: whether an employer's or HR letter is accepted as proof of address by the activating partner. It cannot enter the policy source while it carries the marker (the loader rejects it), so it waits in the proposals file for decision 13. A concern type of its own (tax residency, privacy) would change Jev's classifier question; M2 decides that from the corpus.
- One more thing from that stretch of the call: at line 55 the rep said "we don't share it with anyone else" about the proof of address. The partner does receive KYC data. That needs approved wording or a caution; your call.
2c. "I actually don't know what 'check we can serve them' should be"
What we found. It never ticked in your run and was never marked not needed. Its only done condition is the residency slot (policy/src/plan-onboarding.json:834). The client said "Saudi" at 00:49 and 05:41 and named Saudi National Bank at line 38, but the residency question was answered with confidence in only 2 of the 4 runs (those ticked it at 01:40). Yours never did. The item was the open card for 107.7 s in total with nothing but its hint, because its two situations (works abroad, UK address unclear) never fitted. Tag: policy gap plus design choice. A step whose done condition is a fact, but which reads like an instruction to the rep, can only ever nag.
What it should be: a fact, ticked silently, with no row by default. "Where they live and bank" is something the copilot should know, not something the rep should say. It is satisfied by the country from sign-up or the call and, once the copilot has a slot for it (a new fact question, so a re-ask of the bank), the country of the bank named on the call; it disappears into the chips ("Lives in Saudi Arabia, from sign-up"; "Banks in Saudi Arabia, from the call"). It comes back as a card only when it matters:
- the residency or the bank's country is outside the served list (then the existing approved lines apply, and a kind "we can't serve you" exit is a good outcome);
- sign-up and the call disagree (sign-up says GBP to EUR, the client talks SAR);
- it is still unknown once the discovery part of the call is past.
| Option | What the rep sees on a call like this | Recommendation |
|---|---|---|
| A. A fact, ticked silently, surfaced only in the three cases above (recommended) | Nothing, apart from the chips | Fits "if we believe we can serve them, we don't have to say it" |
| B. Keep it as a step that ticks when the rep asks about residency | Never ticks on calls where the rep does not ask | The dud question you described |
| C. Drop it | Nothing, ever | Loses the "can't serve" exit, which the outcome data shows is worth having |
2d. "Is it okay that some of these get skipped?" and "It's not a checklist, but it's there to help you"
What we found. Yes, and the plan currently punishes exactly that. At line 107 the plan had 3 of 10 template items done, 1 not needed and 6 never ticked, and the must-say counter read 2 of 7. The coach scored this call 4 of 5.
| Item | Why it never ticked | What it really was on this call |
|---|---|---|
| Set the agenda | its only done condition is "delivered" via a situation that never fitted | the rep set the agenda at 00:32-00:43 ("establish what your transfer requirements are and if we'll be the right company") |
| Understand the transfer | needs the purpose slot (2a) | salary, SAR to NZD and CAD, 25-30k NZD plus 5k CAD monthly: all said |
| Check we can serve them | residency slot never filled (2c) | known from sign-up; bank named at line 38 |
| Fund from your own account | needs the rep to say it | implied: salary paid into her own SNB account |
| Who holds the money | needs the rep to say it | really due at 05:37-08:16 when she asked "is it gonna be safe"; the rep answered "please do your own research into our company" (line 109). This is the one genuine coaching moment on the call |
| When the money arrives | needs the rep to say it | worth saying at 06:44-07:32 (paid on the 15th, leaving on the 18th, SAR to NZD is not a major pair), but not a must |
Two things the rep did without a card on screen count for the guide, not against it: documents at line 46 and "booking is binding" at line 89 were both covered before Jev suggested them. And one miss the engine did not catch: the Canada leg, "about 5,000 Canadian every month", is about GBP 2,900 at the policy's rate and so under the GBP 5,000 minimum, but with one amount slot the plan marked "Minimum transfer" not needed at line 13.
What changes: three kinds of item, and the live list stops keeping score.
| Kind | What it is | Ticks how | Shown live | Counted |
|---|---|---|---|---|
| Fact to establish | something the copilot should know (purpose, amounts, where they live and bank, the next step) | silently, from sign-up, the CRM or either speaker | only as a chip once known; a card only if it is missing when it matters | never |
| Must say | a protective or regulatory statement (documents, booking is binding, minimum, who holds the money, own-name account when someone else might pay) | when the rep says it, in any words | listed only while it applies; the card only when it becomes due | after the call, "3 of 4 that applied" |
| Judgement call | the rep's choice (agenda, settlement timing, rate answers) | never | as the card only while its trigger fits; then gone | never |
On this call the live list goes from 10 rows to about 3, the honest after-call score becomes 3 of 4 applicable must-says (or 2 of 3, depending on your minimum ruling below), and "covered before Jev suggested it" reads 2 of 2. No tallies live, no "not needed" group live, no red. The review view keeps all of it, as coaching: each miss with the suggested line and a link to the moment.
Positioning, in the words the rep sees. Titles are outcomes, not orders. Known things are chips, not rows. Nothing that never applied gets a row. Most lines are harvested from CT reps' own calls ("And who is it that you bank with in {country}?" comes from 51 calls by 6 reps), and the review view should say so.
Labels for your approval. New wording under the existing ids; reply id: wording as in policy/LABELS.md, or "approve all". Nothing ships until approved.
Item (plan.template.first_call_after_signup. + id) |
Kind | Title today → proposed | Hint today → proposed | New "known" or "not needed" note |
|---|---|---|---|---|
open_with_agenda |
judgement | Set the agenda → Why we're calling | The client knows what this call is for and how long it takes. → One line on what the call is for; skip it if they're already telling you. | none |
understand_the_transfer |
fact | Understand the transfer → What they're sending, and why | What the transfers are for, the amount and how often, before any explaining. → Sign-up gave us a first answer; confirm it and ask only what's missing. | Known from sign-up |
check_serviceability_first |
fact | Check we can serve them → Where they live and bank | Where they live and bank decides whether a partner can take them on. → Only needs a question if sign-up left it open or it's somewhere we can't serve. | Known from sign-up |
confirm_funding_account |
must say, applying only while someone else might pay (the funding-account fact is a third party, a company account, or unknown) | Fund from your own account → Whose account pays | The money has to come from an account in the client's own name. → Worth a word if anyone else might pay; partners take money only from an account in the client's own name. | Paying from their own account |
explain_who_holds_the_money |
must say | Who holds the money → Who holds their money | The client hears who holds the funds before the call reaches booking. → When they ask whether it's safe, or before they first send money. | Kept for the first transfer |
explain_settlement_and_cutoff |
judgement | When the money arrives → When the money lands | Cut-off and settlement timing for their currencies. → Worth it when they have a date to hit. | none |
explain_booking_is_binding |
must say | Booking is binding → A booking is a live trade | Before the first booking: confirming a trade is a contract. → Before they can book on their own, so a practice booking doesn't cost them. | They can't book yet |
close_the_document_gap |
must say | Documents still needed → Documents in, and when | The account cannot trade until the documents are in; agree when they will be uploaded. → Name what's missing and agree a day; the account can't trade until it's in. | The documents are complete |
minimum_transfer |
must say | Minimum transfer → Amounts under the minimum | Their amount may be below the minimum transfer. → One of their transfers may be under the minimum; better they hear it now. | Every amount is above the minimum |
agree_next_step |
fact | First transfer and next step → A next step with a day | Leave with one concrete action and a time. → One action and a time, agreed in their words. | none |
(agree_next_step ticks on the client's words only: the next-step lock counts a client turn, never a rep proposal, as it has since COPILOT-024.)
New labels:
| id | Proposed text | Where |
|---|---|---|
plan.head.title |
Guide for this call | replaces "Plan for this call" |
plan.head.subtitle |
Adapts as you talk. Use what fits. | under the title |
plan.known.signup |
From sign-up | on a chip loaded before the call |
plan.known.call |
From the call | on a chip the call established |
plan.known.demo |
Seeded for the demo | on a chip typed in by hand for a sample call whose CRM key is empty |
plan.last_suggestion |
Last suggestion | the grey line under a new card that keeps the previous card's suggestion for 12 s (point 3) |
plan.concern.raised_again |
raised again | the state word when a concern reopens (2b) |
plan.fact.bank_country.template |
Banks in {country} | a new chip |
situation.address_ties_me_to_tax_residency.headline |
Will this address tie me to that country? | the tax-residency worry (2b), draft |
situation.address_ties_me_to_tax_residency.hint |
One address is enough; don't push a second one. | draft |
situation.address_ties_me_to_tax_residency.point |
We only need one proof of address, and your {country} one is fine. | draft, [VERIFY] with the partner; stays out of the policy until verified |
Where the proposals live. Outside the policy source, in policy/proposals/2026-09-27.json and on policy/LABELS.md, until you reply: the loader rejects any unapproved text, so a draft under an approved id would stop every policy build. "Approve all" covers the two tables above; it never covers the [VERIFY] line, which waits for decision 13.
The checklist-only ids follow the same kinds: said_payment_reason becomes a fact (you ruled on 2026-09-25 that we need to know what the transfers are for; that is knowing, not saying); said_rate_transparency is a judgement item with the rate situations; said_rm_contact a judgement item at the close; said_quote_lifetime and said_recording_disclosure are never on a first call.
Your decisions (2).
| Decision | Options | Recommendation |
|---|---|---|
| 2a. Which pre-call facts may reps see, and from where | (i) the CT sign-up wizard through pd_ct_id; (ii) Pipedrive; (iii) both |
(i) first: it holds purpose, currencies, volume, frequency and country. Needs your yes on consent |
| 2b. Live list structure | A. Known chips, then Now (one card), then Coming up (up to 3 must-says), then Covered (collapsed); B. chips and the card only, the list lives in the review view; C. keep G's list with kinds, minus counts and the not-needed group | A |
| 2c. Who holds the money | a must-say on every first call, or only when the client raises safety (as here) and otherwise on the first-transfer walkthrough | the second |
| 2d. Fund from your own account | a must-say before every first funding, or a must-say that applies only when the payer is a third party, joint or unclear | the second |
| 2e. The GBP 5,000 minimum | does it apply per currency leg for a monthly salary split (5,000 CAD is about GBP 2,900), and what should the rep say (batch two months?) | needs your ruling before the line is written |
| 2f. Title voice | outcome-phrased ("Who holds their money") or action-phrased ("Explain who holds the money") | outcome-phrased, as in the table |
| 2g. The review view's audience | A. managers only first; B. the rep sees their own review after each call; C. a team leaderboard | B, framed as "ahead of the guide"; against C, because it turns the guide back into a checklist |
| 2h. The Saudi salary segment | its own template overlay (test transfer first, first-payment delays, address worries), or ranked judgement situations inside the first-call template | ranked situations first; an overlay only if the corpus (M2) shows the calls differ |
2e. "Client thinks our rate is too high" at 02:22
What we found: a false positive, and the same one we fixed yesterday for a different signal. At line 30 (02:22) the client was describing what her own bank takes ("that's horrific", the rep agreed). The concern classifier opened a rate concern with confidence 0.53 on that line, while the "client objecting" signal was 0.0 and "rate pressure raised" stayed uncertain at 0.44. Nobody had pushed back on a CurrencyTransfer price; there was no price yet. The plan then carried "Client thinks our rate is too high, raised 02:22, done 03:31" as its second row for the rest of the call. Tag: policy gap. COPILOT-058e taught rate_pressure_raised that a complaint about the client's current bank or provider is not pressure on our rate; the concern classifier has its own question and never learnt it.
What changes. A rate concern needs a CurrencyTransfer price to object to: the classifier's criteria for the rate type exclude complaints about the client's current provider (they feed the alternative-provider situations instead), and the engine opens a rate concern only when "client objecting" or "rate pressure raised" is on. Line 30 of this call becomes a labelled case, so the gate pins it. Story COPILOT-119 in the proposal.
3. "The suggestions of what to say ... disappeared before I could fully read it"
What we found
Suggestions were rare. The engine picked a move on 50 of the 96 decisions, but the plan card carried an open "Worth saying" point on only 12 of them, 3 distinct cards in the whole call. In your first seven minutes you saw two. The customer-success call showed 0 points in 131 decisions across three runs. The reference showed an ungated move card on 34-40 of its 38-42 lines.
The reason is the situation gate: every move's lines now live under situations (named patterns in the client's words), and a situation shows only when Jev rates its fit at 0.6 or above. The moves have no flat lines left. So "Listening" is what a card shows most of the time. Tag: design choice (from the like-for-like restructure, COPILOT-095/095b: an approved line shows only where the client's situation matches), with a bug on top (below).
The one that vanished. "And how much are you looking to transfer?" was on screen, tinted, for 1.0 s (call time 100.3 to 101.3). Reading it needs 6 s. Two things went wrong:
| Step | What happened |
|---|---|
| 01:30-01:39, line 9 (rep) | the rep asked "What's the average amount and frequency that you're planning" |
| the decision on that same rep line | the engine chose the situation "amount not said" and its point, the very question the rep had just asked |
| 100.3 s | the presenter showed it, 1.1 s after the rep finished asking |
| line 11 (rep), "Kiwi dollar." | the point was ticked covered; it went grey, then folded |
That is a stale suggestion (bug): a point born on a rep turn that is already making it should never flash.
The one that disappeared unread by a different route. "When are you looking to make your first transfer?" was on screen for 23 s (110.9 to 134.1) and then removed, uncovered, when the client's next turn raised a problem and the situation's fit fell to 0.05. The client volunteered the date later, at line 71, with no card. The gate is re-judged from scratch on every client turn (src/engine/situation.ts:184-194), and the 20 s dwell protects the card's title, not its points (web/src/presenter.ts:164-170, 176-193). Tag: design choice with a gap: G's cadence rules cover how long a card stays and how long a covered point lingers, and say nothing about an uncovered point being withdrawn. The shortest possible display today is the gap between two client turn ends, 0.48 s on this call; 19 of the 47 such gaps are under 5 s.
Two more timing facts. Of 17 card spans in the call, 4 lasted under 6 s. And one card went the other way: "Fund from your own account" was chosen at 07:44 and shown at 08:33, a 49 s wait, because the dwell rule and a 41 s rep monologue held it back.
One earlier report guessed the vanishing text was the caution (which fades at 12-15 s) or the covered-point fold. Neither: no caution has ever fired on the sample calls, and the measured candidates are the two above.
What changes
- A point stays at least 12 s once revealed, tinted or grey, even if the next decision drops it. (New constant
LIVE_POINT_MIN, new cadence rule inDESIGN.md.) Two things cut the floor short: the rep covering the point (it turns grey and folds as today) and the engine dropping its situation on a clear miss (a fit under 0.3), when it leaves within a second; the floor covers a card switch and the one uncertain miss of rule 5. - Points stack, up to three. A newer situation's point is added under the older one; the oldest leaves first once its 12 s are up, and when a fourth arrives the oldest leaves at once, floor or not. This is the "two or three things worth addressing in one turn" in G's one-card shape. Three 15-word points are about 18 s of reading at 2.5 words a second, so the design board before the screenshots decides between three and two.
- The last suggestion sticks for 12 s after the card switches, as one grey "Last suggestion: ..." line under the new card.
- A point born on a rep turn waits for the next rep-turn decision, or 3 s, whichever comes first. If that decision ticks it covered, it arrives grey, never tinted. (After line 9 the next decision is the two-word client line "Okay. So,", which cannot tick anything; the tick comes with line 11, 1.7 s later, so a plain one-decision wait would still have flashed it.)
- A shown situation survives one uncertain answer. A fit between 0.3 and 0.6, or a question the budget dropped, no longer removes the situation on its own; a second such answer does, and an answer under 0.3 (a clear "not this") removes it at once, as does another situation fitting. This amends your like-for-like rule, which today drops the situation on any answer under 0.6 (decision 17).
- A new card opens with points, not "Listening". The engine pre-judges the item that is about to open: up to 3 extra yes/no questions and, where the item has two or more situations, its situation choice too (without the choice the card would still open on "Listening"; the amount item has two situations). About 1,200 tokens on a client-part request, and the first thing dropped under budget. So the card does not spend its first decision empty, as it did at line 8-9.
Your decision (3): how many suggestions.
| Option | Effect on this call | Recommendation |
|---|---|---|
| A. Keep the gate, add the six rules above | the two cards you saw become readable and stack; a third or fourth card appears where the gate was one decision late | do this first, and measure |
| B. Show the best-fitting situation's core point at a lower fit (0.4 to 0.6) when nothing clears 0.6 | more cards, less specific ones. This loosens your like-for-like rule (an approved line only where the client's situation matches). There are no generic approved lines to fall back on: the restructure moved every approved line into a situation, and the flat lines left are drafts | only if A still feels sparse, and with a check that the delivery-date must-not case stays hidden |
| C. Lower the fit threshold from 0.6 to 0.5 | unmeasured; more cards and more wrong ones | not yet |
4. The player: "catching up, 5 queued" moves the scrubber
What we found: a layout bug. When the session falls behind the clock, the player bar shows "catching up, N queued" inline with the scrubber. The text appears and disappears with the queue, so the scrubber jumps left and right with it.
What changes. The status gets a slot of its own that is always reserved (or sits as an overlay above the bar), so nothing in the player moves when it appears; the design board settles where. Story COPILOT-120.
Decisions that are yours
- (1a) The cadence rule: A, B or C. Recommended A.
- (1b) Whether the card itself may switch at a sentence end. Recommended no: feedback moves, the card waits for the turn.
- (2a) Which pre-call source and fields reps may see before a call, and consent to use them in the copilot.
- (2b) The live list structure: A, B or C. Recommended A.
- (2c) Who holds the money: always on the first call, or when safety is raised. Recommended the second.
- (2d) Fund from your own account: always, or only when the payer is unclear. Recommended the second.
- (2e) The minimum per leg for salary splits, and what the rep should say.
- (2f) Title voice, and the wording table above (approve all, or reply per id).
- (2g) Who sees the review: recommended the rep sees their own.
- (2h) A Saudi segment overlay, or ranked situations. Recommended situations first.
- (3) Suggestion density: A first, then B if needed.
- The wording at line 55 ("we don't share it with anyone else"): approved line or a caution.
- Whether an employer or HR letter counts as proof of address for the activating partner (needed before the tax-residency line can be approved).
- Live audio budget: the paid Workers plan for M3 (the free allowance is about 12 minutes of live audio a day), and about $0.09 of transcription on a ten-minute call on top of the engine's $0.05.
- The hard token cap: keep 12k, or raise it to about 16k so the window can span what the reference saw (about 160 s). Cloudflare served requests up to 15,674 tokens with flat latency; the cap is ours.
- The per-call cost gate: keep $0.05 (the strong calls then lose the pre-judge questions first under budget) or re-set it to $0.06. Engine only; live transcription is on top of either.
- The like-for-like amendment in 3.5: a shown situation survives one answer between 0.3 and 0.6 or one dropped question; under 0.3 it leaves at once.
Open questions we could not settle from the data
- Which view you had open. The "two ticks with different timestamps" reads like the live view's plan list; nothing in the database records the view.
- Which reference mode you compared against. If it was replay (silences capped at 6 s) or the live mic (interim words), the word-by-word transcript alone answers most of point 1.
- The next replay you open may differ slightly from the one you watched: on cache misses the four runs of this call disagree on residency, on rate-versus-fees at line 30, and on one versus two jurisdiction concerns. The proposal makes the concern part deterministic; the residency part is fixed by loading it from sign-up.
- A correction mid-call ("fifty thousand, actually fifteen") and a second transfer in the same call look the same to a plan with one amount slot: the chip reads "updated" for the first and loses the second. Multi-leg slots (M2) fix the second; the first needs a value history, also M2. Until then a second amount keeps the minimum item open rather than waving it through.
- Reps have no dismiss or defer control on a suggestion. Whether they need one is a question for the first team trial, not something to guess now.
- Hold music, talk-over and non-English stretches have no defined behaviour. The M2 corpus will show how often they occur; on Aircall transcripts talk-over lands as interleaved short lines (lines 55-60 here), which the 4-word guard absorbs.