Reference: issues/18972#issuecomment-4478791375
detect_machine casing — investigation
Headline finding
The code matches the hosted documentation. What initially looked like Inconsistency A (lowercase finished among uppercase event values) is documented behavior. What initially looked like Inconsistency B (event channel vs. SWML variable) is two separate documented contracts on two different surfaces.
The reporter's pain is real, but the diagnosis in the GitHub issue was based on a different doc URL (/docs/swml/reference/detect-machine.md) that does not match the hosted page (/docs/swml/reference/calling/detect-machine). On the hosted page the casings line up with the implementation.
The two surfaces and their contracts
| Surface |
Docs say (hosted) |
Code emits |
Source |
calling.call.detect event payload params.detect.params.event |
HUMAN, MACHINE, READY, NOT_READY, UNKNOWN, finished |
same |
relay_detect.c:291, 298, 384, 443, 514-526, 541; relay.c:10644 |
${detect_result} SWML variable |
conditional example uses 'machine', 'human', 'fax' (lowercase) |
machine, human, fax, unknown, detecting, error |
|
Both surfaces are internally self-consistent and consistent with the docs. The trap is that they use different conventions, and a reader doing switch.case on event payloads while expecting them to behave like the variable will be confused.
Where the real problems live (all docs, no code)
1. READY is in the wrong bullet list
The hosted page lists READY and NOT_READY alongside HUMAN, MACHINE, UNKNOWN, and finished as if they're all the same kind of value. They aren't:
HUMAN, MACHINE, UNKNOWN are detection outcomes — final results of an AMD attempt. They also (lowercased) populate ${detect_result}.
READY, NOT_READY are lifecycle markers for the voice-activity layer — they fire as the call transitions between voice and silence and never appear in ${detect_result}. detect_result_to_str has no READY case.
finished is a terminal lifecycle marker — fires once when the detector stops. Also never in ${detect_result}.
Lumping these into one list makes readers think detect_result == 'READY' could match. It can't.
Fix: split the docs list by surface — outcomes vs. lifecycle markers — and make it explicit that READY/NOT_READY/finished only appear in event payloads.
2. The finished casing in docs looks like a typo but isn't
finished is lowercase in a list of otherwise uppercase tokens. Reader instinct is "this is a doc typo, the code probably emits FINISHED." It's not — the code really does emit finished . The docs match.
But it remains weird-looking. Two options if we ever revisit it:
- Tighten the docs to call out that lifecycle markers (
finished) follow a different casing than outcomes (MACHINE). Cheapest.
- Uppercase the code (
FINISHED) for visual consistency. One-line change, but a wire-format break.
Not worth the second option unless we're already touching the wire format for other reasons.
3. The conditional example contradicts the bullet list above it
Same page:
- Bullet list of valid event values:
HUMAN, MACHINE, READY, NOT_READY, UNKNOWN, finished (mostly uppercase)
- Conditional example:
detect_result == 'machine' (lowercase)
These are two different surfaces, but a reader scanning quickly comes away thinking the docs contradict themselves. The fix is to make the surface boundary explicit: "Event payload uses these uppercase values… ${detect_result} carries these lowercase values…"
On the original issue's three asks
-
"Reconcile the runtime validator with the published schema for detect_machine timing parameters." — Addressed by the validator fixes.
-
"Normalize detect_result casing across calling.call.detect, SWML variables, trigger/final events." — No code change recommended. The two surfaces have documented contracts that the code matches. Aligning them would be a wire-format break for marginal benefit; documenting them more clearly costs nothing and solves the reporter's underlying confusion.
-
"Clarify whether READY is a valid detect_result value." — No, it isn't. READY is an event payload lifecycle marker only. ${detect_result} only ever holds machine, human, fax, unknown, detecting, or error. Pure docs clarification.
Recommendation
- Code on this branch: leave casing alone. Ship the validator fixes only.
- Follow-up docs ticket against the hosted reference page covering: split the value list by surface, clarify
READY/NOT_READY/finished are lifecycle-only, align the conditional example with the bullet list (or call out the surface difference explicitly).
- Optional, low-priority code follow-up: if the docs ever standardize on UPPER for the event channel, uppercase
finished → FINISHED to match. Requires a coordinated rollout (Hagrid → Prime → SDKs → docs → customer notice) and is probably not worth doing in isolation.
Reference: issues/18972#issuecomment-4478791375
detect_machinecasing — investigationHeadline finding
The code matches the hosted documentation. What initially looked like Inconsistency A (lowercase
finishedamong uppercase event values) is documented behavior. What initially looked like Inconsistency B (event channel vs. SWML variable) is two separate documented contracts on two different surfaces.The reporter's pain is real, but the diagnosis in the GitHub issue was based on a different doc URL (
/docs/swml/reference/detect-machine.md) that does not match the hosted page (/docs/swml/reference/calling/detect-machine). On the hosted page the casings line up with the implementation.The two surfaces and their contracts
calling.call.detectevent payloadparams.detect.params.eventHUMAN,MACHINE,READY,NOT_READY,UNKNOWN,finishedrelay_detect.c:291, 298, 384, 443, 514-526, 541;relay.c:10644${detect_result}SWML variable'machine','human','fax'(lowercase)machine,human,fax,unknown,detecting,errorBoth surfaces are internally self-consistent and consistent with the docs. The trap is that they use different conventions, and a reader doing
switch.caseon event payloads while expecting them to behave like the variable will be confused.Where the real problems live (all docs, no code)
1.
READYis in the wrong bullet listThe hosted page lists
READYandNOT_READYalongsideHUMAN,MACHINE,UNKNOWN, andfinishedas if they're all the same kind of value. They aren't:HUMAN,MACHINE,UNKNOWNare detection outcomes — final results of an AMD attempt. They also (lowercased) populate${detect_result}.READY,NOT_READYare lifecycle markers for the voice-activity layer — they fire as the call transitions between voice and silence and never appear in${detect_result}.detect_result_to_strhas noREADYcase.finishedis a terminal lifecycle marker — fires once when the detector stops. Also never in${detect_result}.Lumping these into one list makes readers think
detect_result == 'READY'could match. It can't.Fix: split the docs list by surface — outcomes vs. lifecycle markers — and make it explicit that
READY/NOT_READY/finishedonly appear in event payloads.2. The
finishedcasing in docs looks like a typo but isn'tfinishedis lowercase in a list of otherwise uppercase tokens. Reader instinct is "this is a doc typo, the code probably emits FINISHED." It's not — the code really does emitfinished. The docs match.But it remains weird-looking. Two options if we ever revisit it:
finished) follow a different casing than outcomes (MACHINE). Cheapest.FINISHED) for visual consistency. One-line change, but a wire-format break.Not worth the second option unless we're already touching the wire format for other reasons.
3. The conditional example contradicts the bullet list above it
Same page:
HUMAN, MACHINE, READY, NOT_READY, UNKNOWN, finished(mostly uppercase)detect_result == 'machine'(lowercase)These are two different surfaces, but a reader scanning quickly comes away thinking the docs contradict themselves. The fix is to make the surface boundary explicit: "Event payload uses these uppercase values…
${detect_result}carries these lowercase values…"On the original issue's three asks
"Reconcile the runtime validator with the published schema for
detect_machinetiming parameters." — Addressed by the validator fixes."Normalize
detect_resultcasing acrosscalling.call.detect, SWML variables, trigger/final events." — No code change recommended. The two surfaces have documented contracts that the code matches. Aligning them would be a wire-format break for marginal benefit; documenting them more clearly costs nothing and solves the reporter's underlying confusion."Clarify whether
READYis a validdetect_resultvalue." — No, it isn't.READYis an event payload lifecycle marker only.${detect_result}only ever holdsmachine,human,fax,unknown,detecting, orerror. Pure docs clarification.Recommendation
READY/NOT_READY/finishedare lifecycle-only, align the conditional example with the bullet list (or call out the surface difference explicitly).finished→FINISHEDto match. Requires a coordinated rollout (Hagrid → Prime → SDKs → docs → customer notice) and is probably not worth doing in isolation.