Skip to content

NO ANSWER outcome misleading: calls rejected before handset rings report as callee no-answer #105

Open

Description

@DannyBaanks

CALL-E: NO ANSWER outcome misleads when carrier rejects before reaching handset

Summary

When an outbound call fails immediately, the API/CLI returns NO ANSWER
with hangup_type: ByCallee and duration_seconds: 0. This is misleading
because the call never reached the handset — it got rejected before ringing.

Reproduction

Three identical attempts (same plan, same number, same region, 30s apart):

Environment: Windows 11, Node v22.23.1, calle CLI 0.5.0, post-provisioning fix (Issue #103).

calle call plan --to-phone "+52••••••9116" --goal "Say: Danny..." --region MX
calle call run --plan-id <plan_id> --confirm-token <token>
calle call status --run-id <run_id>

Results observed

Attempt run_id Status Hangup Type Duration Callee sees ring?
1 LYI-...TsLA NO ANSWER ByCallee 0s NO
2 1BiD...Hw NO ANSWER ByCallee 0s NO
3 nVI5...EvQ NO ANSWER ByCallee 0s NO

Server-side timeline per run:

[stage_start]    run_call started
[external_call]  botlab create bot
[external_call]  calling resolve robot id
[external_call]  calling create task
[result]         calling task created
[progress]       calling task status=pending
[progress]       calling task status=calling
[callee_realtime] Call ended; syncing final Calling result
[progress]       calling task status=NO ANSWER
[error]          calling task completed with status=NO ANSWER

call_start_time == call_end_time == the same second. duration_seconds: 0.

Request

When a call ends in under 0 seconds with hangup_type: ByCallee before the
device ever rings, we would like:

  1. A distinct outcome or diagnostic value (e.g., NO_ANSWER_NO_RING,
    CARRIER_REJECTED, UNSUPPORTED_DESTINATION, REGION_NOT_SUPPORTED).
  2. If this is simply the carrier's "no coverage in that region" behavior for a
    specific destination, the CLI/docs should say so instead of conflating it
    with "user didn't pick up".

Current behavior

NO ANSWER means "the carrier did not connect to a handset" and conflates:

  • callee actually unanswered (normal failure)
  • callee-side screen/visual voicemail (still an answer to the carrier)
  • carrier rejected the number/regional drop (no ring, no opportunity to answer)

This is particularly deceptive in an SDK: a caller calling e.g. wait_for_result
sees NO ANSWER and assumes the remote device was reached, but @call-e/core
knows the call instantly dropped (ByCallee, 0s).

Behavior expected

A truthful outcome that lets callers distinguish these cases so retry logic and
analytics are correct.

Where the seam is (not a bug, but worth noting)

Not a blocker (we understand this can be implementation-carrier-dependent), but
a useful second-order observation added to the known "[not-call]" patterns:

  • Attempt sequence: plan -> confirm_token -> run_call -> get_call_run
  • Outcome signal: NO ANSWER with ByCallee + 0s duration
  • Missing signal: a "reachability" classification (ringing vs rejected)

Notes

Activity

  1. DannyBaanks commented on Sep 3, 2026

    @DannyBaanks
    ContributorAuthor

    One follow-up thought after seeing how this might be recoverable from a UX angle:

    A coverage endpoint/command could remove a lot of this ambiguity cheaply. For
    example:

    calle coverage
    calle coverage MX
    

    returning something like:

    COUNTRY   OUTBOUND   STATUS
    US        yes        supported
    MX        no         unsupported
    

    Or calle call plan could fail early with:

    ERROR: destination +52 is not currently supported for outbound calls.
    Run `calle coverage MX` for details.
    

    …instead of completing a plan, running a call, and only then returning
    NO ANSWER, which a reader will understand as "the callee could/should have
    picked up" rather than "the carrier never routed to a handset."

    If MX is actually supported, this command would also let us falsify the
    coverage hypothesis — today's 3/3 attempts show NO ANSWER + 0s + ByCallee,
    which is not what we'd expect from "supported."

    This is not a request for new product scope. Just a cheap UX waypoint that
    would let callers fail fast and know why.

  2. Ray-56 commented on Sep 4, 2026

    @Ray-56
    Collaborator

    Priority: P2 — incorrect terminal classification can drive misleading analytics and unsafe retry policy. There is no evidence of duplicate calls in this report, but callers may reasonably retry NO_ANSWER; that becomes a real-world side-effect risk when the platform has not established whether the carrier rejected the leg, the endpoint declined it, or signaling was ambiguous.

    The repository currently lists Mexico (MX, +52) as a supported Local region, so these results should not be documented as unsupported coverage without platform/provider evidence. Also, duration_seconds: 0 plus hangup_type: ByCallee is not sufficient by itself to prove a carrier rejection: timestamps may be coarse, and an immediate endpoint decline can produce the same surface values.

    Recommended remediation:

    1. Capture and retain the provider-leg milestones used for classification: carrier accepted, alerting/ringing, answered, and the terminal SIP/Q.850/provider cause. Redact provider identifiers and phone data from user-visible logs.
    2. Reserve NO_ANSWER for a leg that reached alerting/ringing and then timed out without an answer. For a pre-alerting failure, return a failure outcome with a stable machine-readable reason such as CARRIER_REJECTED, DESTINATION_UNREACHABLE, or ROUTE_UNAVAILABLE. Include fields such as failure_stage, reached_ringing, and an explicitly derived retry_safe value; preserve the existing terminal status during a compatibility window if needed.
    3. Treat missing or contradictory provider evidence as unknown and non-auto-retryable. Clients should keep the original run_id and query it rather than submit another real call.
    4. Add a classification matrix test covering pre-alert carrier rejection, remote decline, normal no-answer after ringing, voicemail, busy, and ambiguous/late provider events. Add a live route check for the reported Mexico path and verify that the public status, failure reason, duration, and retry guidance agree.
    5. If coverage availability is dynamic, expose it from the platform as the source of truth before adding a CLI preflight. A new calle coverage command would be a separate backward-compatible feature, not a substitute for correct terminal classification.

    This appears to be a deployed calling-platform result-mapping issue, so no repository package release is needed for a backend-only fix. If the public MCP contract or packaged CLI/skill guidance changes, run the release-decision checklist; a new CLI command or public status capability would normally require a minor release, while a backward-compatible documentation/mapping correction would normally be a patch.

  3. Ray-56 commented on Sep 4, 2026

    @Ray-56
    Collaborator

    P2 privacy note: the reproduction currently publishes a complete destination phone number. Unless this is a documented non-personal test number that is safe to disclose, please redact it to the country code plus masked suffix (for example, +52••••••9116). Keep the full value only in a restricted support channel if maintainers need it for provider tracing. The abbreviated run IDs are appropriately masked; provider call IDs, account identifiers, tokens, and raw call logs should likewise stay out of the public Issue.

  4. DannyBaanks commented on Sep 4, 2026

    @DannyBaanks
    ContributorAuthor

    Privacy fix done per your note: the destination number in the reproduction is now redacted to +52••••••9116\ (issue body edited). Provider-side \call_id\ values in our local evidence mirror were also redacted (commit). Full value retained locally only, available via a private channel if you need it for provider tracing.

    Walking back the classification claim per your P2 guidance: \duration_seconds: 0\ + \ByCallee\ does NOT prove carrier rejection, and MX is listed as a supported Local region — so we withdraw any implication of unsupported coverage. What remains observed is only: three attempts terminated in \NO ANSWER\ with 0s duration and no handset ring on a supported region, i.e. the
    eached_ringing\ signal is what is missing from the user-visible outcome. We leave terminal-classification design (failure_stage / retry_safe semantics) to your remediation item 1-3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions