Inspiration

A cancelled appointment leaves a practice with a deceptively simple job: call an opted-in waitlist until somebody accepts the slot. The dangerous case is not the happy call. It is the timeout, restart, late result, or cancellation in the middle. If software guesses, it can offer the same slot twice; if it gives up, staff return to a half-finished list with no reliable explanation.

We built Continuum Call around that uncertainty. It is appointment logistics, not medical advice, and it never calls a verbal confirmation "booked" because there is no calendar writeback.

What it does

  • Models each business step as a CallTask, each authorized semantic attempt as a CallIntent, and each provider execution as a ProviderRun.
  • Freezes and hashes the canonical call payload before dispatch; recovery rebuilds that exact payload and reuses the same provider idempotency key.
  • Blocks the next waitlist candidate while an upstream result is ambiguous or unresolved.
  • Applies consent, E.164 allowlist, IANA timezone, calling-hours, call-cap, and global-stop guards before dispatch and recovery.
  • Keeps in-flight work visible during cancellation instead of pretending it disappeared.
  • Carries confirmed facts with source-intent and source-run provenance into a second-party call.
  • Exports a hash-chained Evidence Pack whose application-level verifier replays events, recomputes state, compares the ledger, checks provenance, and rejects partial tampering. The demo chain is not signed or externally anchored and is not presented as cryptographic authenticity.

What makes it different

Idempotency keys, crash recovery, and hash chains are necessary reliability primitives, but they are not the product by themselves. Continuum Call composes them into one inspectable runtime for more than one multi-call mission:

  • a frozen mission-graph snapshot separates a running mission from later template edits;
  • CallTask -> CallIntent -> ProviderRun separates policy retries from infrastructure recovery;
  • intent lifecycle, provider progress, and business outcome remain independent axes;
  • downstream calls consume only resolved, provenance-linked facts;
  • the same operator and verification contracts cover Slot Recovery and Cross-Party Handoff.

The result is a narrow control plane for phone missions, not a generic workflow engine and not another single-purpose caller.

How we built it

The local application is TypeScript on Node 22 with node:sqlite durability. MissionRuntime owns transitions and append-only events; IntentDispatcher enforces guards and provider creation; MissionReconciler recovers stuck intents from frozen state. A CALL-E adapter uses the official Developer API with bearer authentication and Idempotency-Key on POST /v1/calls, plus GET /v1/calls/{id} for status and structured results.

The Ops Console makes the failure model visual. Its deterministic fault lab injects a failure after mock-provider acceptance but before the local run ID is attached, discards in-memory runtime objects, reloads SQLite, and reconciles the same key. A separate ambiguity proof keeps waitlist C pending. The evidence verifier then proves the stored result from the event history and rejects five classes of manipulated evidence.

The submitted runnable package is apps/typescript/continuum-call.

CALL-E runtime proof

On 13 September 2026 the submitted runtime ran against the live CALL-E API with a real key. The operator action is npx tsx scripts/spike/live-runtime-verify.ts live, which drives MissionRuntime to IntentDispatcher to LiveCalleAdapter - the same path the mock UI exercises, with only the adapter swapped.

Authentication was accepted: a read-only GET /v1/calls/<unknown id> returned HTTP 404 not_found. POST /v1/calls never produced a call. The first attempt exceeded the adapter's 15-second request timeout and was recorded as ambiguous with no provider run. With the timeout raised to 60 seconds, CALL-E answered HTTP 422 call_not_ready twice: first that Germany with German is not a supported region/language combination, then that an English call to a recognized Germany number is not supported either.

What this proves: the submitted runtime performs authenticated live CALL-E requests, freezes one canonical payload under a stable idempotency key, reserves exactly one create before any network I/O, and turns a provider refusal into an explicitly unresolved intent that blocks the mission. What it does not prove: provider idempotency, ring-start semantics, or any completed conversation - no call was created. The provider dashboard shows 0 call records for 11-13 September 2026 and the ledger still reads 20 of 20 free calls.

Every repeat-call claim in this submission therefore stays scoped to the deterministic mock lab.

Challenges

The hardest part was designing a reusable mission model without collapsing three facts that look deceptively similar: lifecycle state, provider state, and business outcome. "The request timed out" does not mean no phone call exists, and an early "yes, speaking" is not acceptance of a slot. That led to fail-closed transitions, immutable payloads, and a cancellation state that keeps uncertain work visible.

The second challenge was making reliability inspectable. A log can repeat the same incorrect conclusion. Our verifier therefore derives the conclusion again from the event history and checks it against the exported ledger.

Accomplishments

  • F1-F12 named failure matrix passes in the deterministic mock lab.
  • Payload changes under the same intent are rejected.
  • SQLite rebuild and same-key mock reconciliation are visible in the UI; an HTTP contract test additionally kills and restarts a real local Node process against the same SQLite file.
  • Unresolved upstream work produces zero illegal conflicting unlocks in the tested histories.
  • Cross-party facts remain traceable to their source call.
  • The tamper matrix rejects hash, metadata, run-ownership, provenance, cancellation, and illegal-unlock mutations as expected.
  • Eleven focused hardening regressions pass with mock/stubbed networking only.
  • 10,000 deterministic chaos schedules completed with 0 failures and 0 illegal unlocks.
  • TypeScript checking and the complete local test suite pass with 0 live calls during simulation.
  • Five authorized live attempts produced zero created calls, zero duplicate dispatches and zero invented outcomes. Two were refused by the runtime's own controls before any network I/O: once because an unresolved mission still held the task, once because the persistent one-shot reservation had already claimed the single allowed create.

What we learned

Exactly-once telephony is the wrong promise. The useful abstraction is a stable semantic intent, a frozen request, explicit ambiguity, and a recovery policy that never invents certainty. Product language matters too: Provider Runs is defensible before ring-start semantics are known, and verbally_confirmed is honest when no calendar system was updated.

Real-world impact

The immediate user is the person coordinating appointment slots by phone. The broader opportunity is any phone workflow where repeating an action or acting on an uncertain result has a real cost: service dispatch, exception follow-up, or multi-party coordination. One runtime can support those templates while keeping the same recovery, operator, and evidence contract.

Measured during the live session rather than estimated: identifying the stuck intent took one read of the exported event chain, which named the transition, the reason code and the exact second it fired. Clearing it was a deliberate operator action that the runtime refused to perform on its own - the one-shot reservation is never removed automatically, so a retry required reconciling the provider dashboard against the local ledger first. Across the whole session no step required guessing whether a call existed.

What's next

  • Validate CALL-E idempotency and lost-response behavior against controlled live calls.
  • Move the durable runtime from local SQLite to a hosted persistence path.
  • Add calendar writeback before exposing a true booked outcome.
  • Turn operator feedback into clearer exception queues, not more autonomous calling.

Built With

Share this project:

Updates

Submission history