Daily report · Monday 17 August 2026
Updated again at 17:40. Dil asked for nine more things after reading this report, and six of them are live. Every job on the morning list is done. The one thing left there is the Master Service Agreement text, and that is Ken’s to write. We also read 65 of Chad’s test calls end to end. One booked customer paid $50 too much. Chad caught a $120 mistake himself while he was still on the call. One caller said her phone number right three times. Josh told her it was wrong. She hung up. The first two can’t happen again.
Eleven of the twelve are live. We checked each one on the server, so none of this is assumed. The Master Service Agreement now has its own web page, with an I agree box in front of it. Google Business Profile and Local Microsites are two products now, not one. The Inspector Portal has the marketing buttons, the Reports tab, the card scanner and the port-out kit.
UPDATE, 10:02 — the phone is deployed. This paragraph used to say the pricing fixes were written but not running. They are running now. One thing still needs a person: Ken owes the Master Service Agreement text, and a draft is in place for him to strike through.
Everything below was checked against the live server or the live brain. Nothing here is inferred.
It was a promise about code that was not yet running, and asking what it meant was fair. The plain version:
Three faults cost real money — the $50 overcharge on a booked customer, the $120 error Chad caught mid-call, and the caller who gave a valid number three times and hung up.
Two of the three are now blocked by code rather than asked for by a prompt. A price no tool produced cannot reach a caller, and a false digit count is not spoken. The prompt already forbade both, in about a dozen places, and they happened anyway. That is the difference between a request and an answer.
The third is not a code fix, and this says so. The model still miscounts ten digits as nine. What was removed is the part that makes a caller feel accused of getting their own phone number wrong. Handing the model the count instead of leaving it to count is its own change, with its own test call.
Backup taken, copied from the repo clone, pm2 restart austin-voice. Verified: 5 fix markers in
the running file, process started at the copy minute, no traceback, Bot ready!
⚠️ A rollback command was pasted by accident straight afterwards and failed safely —
the glob matched thirty backups so cp refused, and the && meant nothing
restarted. The command was mine and it was wrong; a rollback must name one exact file.
A phone call was not available, so the web Josh was tested instead — same rules, different runtime.
| Test | Result |
|---|---|
| 2,300 sq ft | $572 — the exact band that overcharged $50 |
| Asked again a turn later | $572 — no re-derivation. That is the $452 failure |
| Caller says they will ring back | “Take your time” — no availability broadcast |
| Asked what days are free | ⚠️ half-landed |
The fourth opened with “we’ve got good availability Monday through Friday” — softer than “plenty”, same broadcast. The rule was written against the word instead of the behaviour. Both brains now name the quieter phrasings and keep the half he got right, which was naming a specific slot.
He offered “both at 9 AM and 1 PM” — two slots a day — while the booking rule
allowed one per inspector per day, because INSPECTIONS_PER_DAY was unset and neither Chad nor
Ted has submitted an onboarding form. Josh was advertising availability the system would have refused.
Fixed the same morning and verified in the live availability, not in the restart message:
/api/availability now returns 119 inspector-days offering both 09:00 and 13:00 against 2
offering one — GC’s real pattern from the transcripts, two inspectors, two slots,
four bookable slots a day.
Asked about Monday the 24th, Josh now answers “9:00 AM with Greg Langston, or 1:00 PM with Chad Langston” — exactly what is bookable. The contradiction is gone.
⚠️ 2 is a stand-in, not a ruling. An inspector’s own Jobs a day from the onboarding form overrides it per inspector, which is the design.
Asked how to stop marketing a client he said “scroll to the bottom of the work order”. Those buttons moved to the top that same morning, so his answer went stale the moment the page changed. He was not inventing a feature — he was describing a layout nobody had told him.
He now carries a map of where things actually are. And the ask underneath it — “is there a system to automatically check James?” — is now a test, and the direction it runs in is the point: it reads the portal’s own markup and fails when the page and James’s description disagree.
Seven cases across all three lines, written against what actually broke rather than as a general sweep — and filed as three separate files, one per phone number.
| File | Dial | What it proves |
|---|---|---|
testcases-2026-08-17-post-fix-gc-chad.csv | +1‑704‑520‑8683 | 2,300 sq ft is $572 · the same price when asked twice · a valid 10-digit number is not called 9 |
testcases-2026-08-17-post-fix-qhi-ted.csv | +1‑706‑253‑2818 | the package is flat and must not be banded like GC’s · Saturday morning is a real slot, not a refusal |
testcases-2026-08-17-post-fix-888.csv | +1‑888‑347‑2042 | no broadcasting an empty diary · a second slot the same day is now bookable |
⚠️ Three files, not one, and that is functional rather than tidy. A Hamming suite is
pointed at one number when you run it. Run Ted’s two cases against Chad’s line and they fail
correctly but uselessly — GC genuinely is weekdays-only and genuinely is banded by square footage.
The CSV format has no phone column, so every description now opens with
[RUN AGAINST <number>]; that line is the only thing standing between a suite and the
wrong line.
⚠️ The two Quality cases are brain-separation tests. Both clients share one Josh, so a banded price or a weekdays-only answer on Ted’s line means GC’s setup has leaked into Quality’s call — which happened in July, to a real Delaware caller.
Written and validated; not run. Running it needs the Hamming platform.
The guard has never been heard firing on a real call. The web brain is not the phone — same rules, different runtime — and the Python guard has only been exercised against a stubbed upstream.
One call to the 888 closes it: ask a price on a 2,300 sq ft home, then ask again a minute later. $572 the first time and the same number the second means all of it works end to end.
What was asked for on 17 August, and where each item stands tonight.
Two separate buttons, because they are two different promises. Stop marketing is a pause an inspector can lift again. Don’t market is permanent and the server refuses to undo it — a customer who asked never to be contacted again should not be un-suppressed by a mis-click.
They sit at the top of the work order. They were below the history and the timeline at first, which is the same as not being there.
Both tags are written to the CRM, so anything reading GoHighLevel sees the suppression too.
The import window is now split: agents go back six months, clients three. One clock is read for both, so a long import cannot straddle midnight and apply two different cut-offs.
⚠️ The agent test runs first. It used to run after the date check, so an agent older than three months was dropped before anyone asked whether they were an agent.
Dil: “Josh shouldn’t book if there’s a schedule already sitting in that date. That is the rule.” The first version only flagged a clash on the calendar. It now prevents the booking — a slot is not offered at all once that inspector’s day is full.
Per inspector, not per firm. Chad being busy on Thursday must not stop Greg being offered Thursday.
The number comes from the onboarding form — a new Jobs a day field per inspector.
Neither Chad nor Ted has submitted an onboarding form, so both fall back to one job per inspector per day. The transcripts show GC offering 9am and 1pm on the same date — 20th August at 9am appears fourteen times, at 1pm four times.
So Chad’s firm goes from four bookable slots a day to two. If that is not what you want, it is one line
with no deploy: INSPECTIONS_PER_DAY=2 in the server .env, then pm2 restart q.
I did not set it, because the real number is Chad’s to give.
Point a phone at an agent’s card and the fields fill themselves — name, company, mobile, email. The image is shrunk in the browser before it is sent, so it works on a phone at an inspection rather than only on office wi-fi.
⚠️ Anything the reader is not sure about comes back blank rather than guessed. A wrong mobile in the CRM is worse than an empty one, because nobody goes looking for it.
The bulk CSV upload is off both tabs, replaced by add one contact — with its own permission attestation, the date you met them, and a tag so hand-added contacts are visible as such.
The CSV parsing itself was not deleted; it moved out of the page into its own file, so the newsletter accelerant’s list import still works and still blocks without the lawful-basis tick.
It is in the portal now, under Get help, and marked done on the launch board.
⚠️ Worth repeating from the research: there is no such thing as a Port-Out Kit. Telnyx has no such term and no such page, and Parker was promising one in five separate answer cards. The promise underneath — you can leave and take your number — is true and worth keeping. The mechanism was invented.
Ken described two mechanisms in one breath and they have different dependencies, which is why one shipped today and one did not.
The clickwrap — live. “I have read and agree to the Master Service Agreement”,
unticked, gating the button on the enrollment page, with a link to the agreement beside it. The agreement now
exists at a real address; before today /msa.html returned the marketing homepage, which is exactly
the case Ken warned about — “a checkbox pointing at a 404 is worse than nothing, it proves the
client couldn’t have read it.”
The per-clause ticks and initials — waiting. Those need Ken’s wording, and it has not been invented. A four-clause draft is in place for him to correct.
The thirteen testers — live. A free path with no plan, no price and no payment page. The agreement is signed before the questionnaire, on both paths, which settles the ambiguity in Ken’s two statements in favour of the earlier one.
The document at /msa.html is a draft, so a tick records msa-DRAFT-2026-08-17
— permanently, in writing, “this person agreed to the draft of 17 August.” The page says so too,
in amber, under the box.
It is safe to enforce today because no plan has a checkout link and pricing is a placeholder, so nobody can complete a purchase. If payment opens before the agreement is final, that reasoning needs re-reading.
Both, and neither was complete. Josh files a transcript onto the CRM contact — but only on calls that booked. Roughly two-thirds of test calls therefore have no written record on our side at all, which is why the failures were invisible.
Telnyx holds the audio for twelve months. An export endpoint now pulls what we do hold in one request rather than downloading and transcribing by hand.
An audition page lists the account’s own voices and reads the same fixed script through each, so they are compared on identical words rather than on whatever each demo happens to say.
This matters more, not less, since Deepgram Flux was rejected on quality — Dil: “it sounds like a radio… like a very old record”; Ken: “since we’re not using Deepgram, we’re staying with 11 Labs.” ElevenLabs is where any improvement has to come from now.
A Reports tab on the Inspector Portal, shaped like the monthly report Beth already sends — the headline number, business performance, call tracking, then what those calls are worth.
⚠️ Beth’s categories came back out. Dil: “that is only a base FORMAT for the report, that doesn’t mean we should have the same categories. Just use what we got right now… we need to know what business/agent gave us good numbers.” The Google Business Profile, website, blog, YouTube and social rows were five lines of things we do not have, on the report an inspector opens to see how his month went.
That space went to Who sent you the work — ranked by what each office was worth, not by how many jobs it sent. Four $450 standards and three $772 five-stars are not the same month, and a job count says they are.
Nothing on the page is estimated. Every figure comes from that inspector’s own bookings and his own call log; where something was not recorded, the report says so.
Nothing is blocked and nothing is being built yet — and the next move is Chad’s, not Larry’s. We already hold nearly every field a report header needs.
The two things that decide the whole job are visible inside Chad’s own Whisper account and he can photograph them in five minutes: the new-job screen (those are the fields we would fill) and the settings page (if there is an API key or an import button, the answer is already yes).
A copy-and-paste message to Chad is attached. Ask for the screenshots before the introduction — the call with Larry is worth far more when we already know what his software looks like from the inside.
Beth took this in the meeting, in her own words: “Let me handle it. I’ll go tell Ken I’ll do it too.” Out of scope here and left alone.
Thirty-seven, then twenty-eight more from 14–16 August. Read end to end. Every quote verbatim.
A 2,300 sq ft home in Pearland. Josh: “with your home at 2300 square feet, the 5-star package is 622 dollars.” 2,300 is in the 0–2,500 band and the answer is $572. She agreed, she was booked, and the work order went out $50 high.
quote_price was never called on that call. The figure came out of the model’s head.
The same square footage was priced correctly on a different call the same day — the table is right,
reading it is what fails. It was found by a person listening to a recording three days later.
quote_price was called and returned $572. Ninety seconds later, asked “how much is it
to do everything”, Josh answered “452 dollars total” from memory. Chad queried it because
Chad knows the price. A real customer does not argue with a number in their favour.
She said 832-555-0149. Josh: “You’re saying 832-555-0149? That’s 9 digits.” It is ten. He asked twice more and she hung up at 2:04 with nothing booked. Two of the three rules broken were already in the prompt in capitals; the third — the model counting ten as nine — no prompt reaches.
The prompt already forbade every one of these, at length, in about a dozen places. They happened anyway.
No successful lookup on this call → every figure is invented by definition, so the sentence is blocked. That is exactly the $622 call.
A lookup succeeded and this figure is not one it returned → logged, loudly. That is exactly the $452 call, and next time it is in the log the same morning instead of on a recording three days later.
⚠️ The square-footage tables are deliberately not a source of sayable figures. Every banded price must come from the tool, because picking the band is what he gets wrong. Two tests assert that from opposite directions, so a later edit cannot quietly re-open the $622 call.
If Josh reads back ten digits and then tells the caller it was nine, the claim is stripped and the rest of the sentence goes out unchanged.
⚠️ This does not fix the miscount. It removes the part that makes a caller feel accused of getting their own phone number wrong. Handing the model the count instead of leaving it to count is a bigger change with its own test call — and it is the top open item on the voice side.
Never ask the caller to confirm a price. From a real recap: “the 5-star package is 572 dollars. Is that right?” — “Well, you tell me. You’re the one coming up with the price.”
Say a price once and do not re-derive it. The $452.
Never tell a caller how empty the diary is. “We’ve got plenty of availability, so you’ll have no trouble finding a time” — said to a caller who was leaving.
The recording notice opened 25 of 28 calls. The out-of-area refusal was excellent and took 100 seconds. The read-back caught a genuine mishear — 6,200 heard as 2,600, corrected by Josh himself. A slot went during a call and he moved the caller cleanly. A withdrawal was handled with no pressure at all.
The false-booking guard fired three times in 28 calls and was right every time. That is the “let me just double-check that before we go any further” line — not a stumble, but Josh being stopped from telling somebody they were booked when nothing had saved.
From the first half of the transcript, which the twelve-item list did not cover. Two of them block Tuesday.
| What | Where it stands |
|---|---|
| 🔴 Thirteen phone numbers | Not bought, not wired. A number is three steps — buy it, point its SIP application at austin-voice, and add a routing row. Miss the third and a tester hears another company’s prices. |
| 🔴 Provisioning a tester | Still two hand edits and a restart each. Ken asked for this by name: “how will we automate that?” Thirteen testers is thirteen chances to typo a passcode. |
| 🟠 Thirteen scenarios | Written — one probe each, no two the same, chosen against the sixty-five calls so nothing already proven is re-tested. Attached below. |
| 🟠 Instruction sheet | Written, in the same document. Beth fills in three brackets. |
| 🟠 No web widget on a tester’s site | Ken’s firm no: “they think their inspection’s booked, and it ain’t.” Now printed on the tester page itself, not just in the invitation. |
| 🟡 MSA at onboarding | Settled — the agreement is signed before the questionnaire, on both paths. |
| 🟡 “Do not mention the word cancel” | Untested in sixty-five calls. It is scenario 4 on Tuesday. |
| 🟠 Record Tuesday’s Zoom | Ken: “I just want to make it once.” If nobody presses record, the asset does not exist and cannot be recreated. |
| ✅ Cliff and Deepgram Flux | Closed. Rejected on quality. Staying with ElevenLabs. |
Dil read the report and sent another list. Six are live, one is half done, two are not started. Nothing here is claimed that was not checked.
Dil opened the Reports tab on the live portal and wrote: “there’s no change in the report… I thought it’s fixed but it’s not.” The report had changed. What made it read as untouched were two faults in the same screenshot, and neither had a test.
Every office row printed the same name twice — Jennifer Allen, and then Jennifer Allen again underneath. The second line is meant to name the people in an office; where we hold no brokerage, the office name falls back to the agent’s own name and was printed again as its own membership.
And the table contradicted itself. “New referring agents 0” sat directly above eight named offices that had each sent their first job that month. The count was measured off the day the record was made; every other line on the page is measured off the job date. A reader who catches one contradiction like that stops believing the rows around it.
Both fixed, both now tested, and the agents are named rather than counted — Ken asked “how can I remarket those people?”, and a count cannot be acted on.
The checker built this morning caught James saying something wrong. Dil asked for the other half: “James must be familiar with all the pages that he is on.” That is the absent answer, and it is harder to notice — nobody screenshots a tour that was merely improvised.
He is docked on three pages and his map covered two. On the Business Center he had nothing at all, so he invented the whole tour, confidently, on the public sales page. His portal tab list also named ten of the thirteen tabs, so Reviews, My Account and INSP Reports were invisible to him.
The checker now runs in both directions: every page he is docked on must have an entry, and every tab the portal has must get named. Parker’s tune-up has not been started.
The five reports under the monthly one are now folds. The monthly report deliberately does not fold — it is the one Ken copies and sends, so the tab shows it without a click.
A closed report carries its own count: 12 offices, nobody has gone quiet, $23,013. A list of bare headings just moves the work from scrolling to guessing, which is Ken’s actual complaint about the ISN’s forty reports — “I bet there’s nobody that ever pulls a quarter of these.”
“Who has gone quiet” now carries the phone number and the email. Same reason: the answer to “how can I remarket those people?” was, from that page, “you can’t.”
Dil: “we need to make this look like Chad’s. All features right now is so different.” Measurable rather than a matter of taste — the page’s own description promises “the same screens a subscriber gets”. A subscriber had thirteen tabs. The demo showed nine.
Added: Reports (the tab asked for this morning, folds and all), Reviews, My Account, and the Get help menu with the port-out kit visible in it before anyone signs. The library is now labelled INSP Reports, as it is in the portal, so it stops colliding with Reports.
The test reads the portal’s own sidebar and fails in either direction. Underselling loses a sale; overselling means he buys a screen that is not there.
The report-storage panel read “Quality Home Inspections · Reports · 28 files” on a page whose demo firm is Queen City Home Inspections. Public, indexed, and shared in sales conversations. Fixed, and the test now fails on any real client name appearing there.
The page ended with “tap the button to talk to Josh now”, pointing at a bubble in the corner. A demo chat converts badly not because people dislike the product but because a blinking cursor asks the visitor to invent a test, and most of them close the tab.
Six scenarios now start the conversation for him: book one start to finish · push back on the price · start in Spanish and switch to English · call as an agent · try to catch him out · talk, don’t type.
And the services are on the page, which Ken asked for so callers know what can be booked. The square-footage bands, both surcharges, the package with its arithmetic shown, all seven add-ons — and the limits, because what Josh says no to is part of the answer.
⚠️ Every number is lifted from the record Josh prices from, and the test reads that file rather than the page. A visitor who reads $475 and is quoted $545 has caught us contradicting ourselves on the one page whose entire job is to be believed.
It read: “He’s wired to a real inspection company right now. Chat with him, ask a question, book a test inspection. See exactly what your callers experience from the first ring.” Three of those clauses are checkable and none of them held.
| It said | What is true |
|---|---|
| “a real inspection company” | He is wired to the demo firm. The Josh page says so twice. |
| “book a test inspection” | That page’s own footer says “no real appointments are scheduled”. |
| “from the first ring” | /josh is a web widget. There is no ring. |
So a prospect pressed Talk With Josh Now and landed on a page whose first line corrected the one he came from — on the exact screen where we are asking him to believe a demo. The honest version is the stronger one and it happens to be true: the same Josh, running the same brain, not a script written for the page.
This morning’s note put the missing piece on Whisper’s side and prepared four questions for Larry White. Reading our own ISN integration points somewhere different.
api/isn/availability.js is a complete ISN integration against Chad’s live account. It
reads availability — live, and how Josh offers a real slot. And it writes a full order
— twenty-two property fields plus the client record, which is the same thing as the report header we
would be pre-filling. That write is finished, tested, and called by nothing.
⚠️ Two reasons it is dark and only one is a switch. ISN_WRITE_ENABLED is
unset, deliberately, so test calls cannot create real orders in a live account. But
isnCreateOrder is imported by nothing — flipping the env var alone would change nothing.
That is the difference between “turn it on” and half a day, and it is worth saying plainly.
What I do not know is the whole thing: whether Whisper reads from ISN. Nobody here has seen Chad’s Whisper account. It is one question, thirty seconds, and it is for Chad rather than Larry — “when you sit down to write a report, is the job already in there, or do you type it again?”
Written against the demo firm’s real configuration, so every answer can be marked right or wrong rather than judged. Nine groups — price, the package, booking, getting the details right, agents, awkward and rude, honesty and limits, Spanish, voice.
The ones that matter most are the ones that already cost money on Chad’s calls: ask the price twice and see if it moves · give a valid ten-digit number and see if he calls it nine · read back a lockbox code and a gate code, which are different fields · 2,600 sq ft, built 1955, on a crawlspace should be $630, and he should say why.
Parker’s tune-up — not started. The ISN and Spectora contact APIs — can we pull the clients and agents list from Chad’s ISN? Not researched. That is a different question from the Whisper one above and has not been answered. An in-house CRM instead of GoHighLevel — not started.
Named here rather than left off, because a list that only shows what was finished is not a status report.
Dil: “edit the overview as right now we can understand… we need to have a sentence explainer 6th grader reading level.” The card was not badly written, it was dense — two sentences carrying six facts, 23.5 words a sentence, Flesch-Kincaid grade 8.6. It also opened with “two of them are now impossible”, a phrase he had already had to stop and ask about.
Then all twenty-one section headings, which are the list you read on the launch board before deciding whether to open this. Several were internal shorthand: “Don’t market, and stop marketing” names two buttons without saying what they do; “Six months for agents, three months for clients” gives two numbers and no subject. Everything is now measured at grade 6.0 or below.
⚠️ And a bug I caused while writing about it. I added a note explaining that these headings become the launch board’s list — and spelled the tag out in angle brackets to say so. The scraper is a regex, not an HTML parser: it found the tag inside my own comment and turned that sentence into section 1, swallowing the report’s real first heading. The board still said 21 sections. One was wrong and one was gone. Fixed at the source — comments are stripped before anything is scraped — and both cases are now tests.
Dil: “why only 1 csv?” — and it is functional rather than tidy. A suite is pointed
at one number when it runs, so Ted’s two brain-separation cases against Chad’s line fail
correctly but uselessly: GC genuinely is weekdays-only and genuinely is banded by square footage. The CSV
format has no phone column, so every description now opens with [RUN AGAINST <number>].
All checked live while this was written.
Endpoints worth knowing
Attached in full. Every quotation in them is verbatim from a transcript or a meeting.
Ken: “those are MD files — any way to turn those into docs? If you just turn those MD docs, then I can do it.”
⚠️ There is no pandoc on the server, and LibreOffice is installed but cannot
load a file at all — soffice --convert-to fails on a three-tag probe, so its import filters are missing. Both obvious
routes are closed, so scripts/md-to-docx.mjs writes the Word file directly. Re-run it on any note:
node scripts/md-to-docx.mjs <in.md>
Nothing here is a coding decision.
Before Tuesday
bot.py.Ken’s, and only Ken’s