Skip to content

fix(voice-call): resolve completed calls from the persisted store on status misses#99797

Merged
steipete merged 5 commits into
openclaw:mainfrom
Darren2030:claude/96586-voicecall-status-persisted-fallback
Jul 5, 2026
Merged

fix(voice-call): resolve completed calls from the persisted store on status misses#99797
steipete merged 5 commits into
openclaw:mainfrom
Darren2030:claude/96586-voicecall-status-persisted-fallback

Conversation

@Darren2030

@Darren2030 Darren2030 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where voice-call status lookups reported { found: false } for calls that had completed successfully and had a full transcript persisted to disk. Once a call was evicted from the in-memory call manager (after finalize, a gateway restart, or max-duration expiry), the lookups only checked memory and never fell back to the persisted store, so the agent/operator could not retrieve the conversation.

Why This Change Was Made

All FOUR status-lookup sites now fall back to the persisted call history when the in-memory manager has no entry, resolving the NEWEST matching snapshot:

  • the voicecall.status gateway method,
  • the voice_call tool get_status action,
  • the legacy mode: "status" tool branch, and
  • the local CLI voicecall status gateway-unavailable fallback.

History is returned oldest-first, so the lookup uses toReversed().find(...) — a forward find() would return a stale/older snapshot. This mirrors the existing describeHistoricalCall helper. The CLI fallback previously consulted only getCall(callId) (narrower than the gateway path), so it now also consults getCallByProviderCallId, aligning all four readers.

Per review on #96586: the CLI path must agree with the gateway/tool paths, so the CLI fallback is included here rather than split out. Note the existing stalled PR #96624 takes the same direction but selects the oldest snapshot via events.find(); this change resolves the newest snapshot instead.

User Impact

Operators and agents can retrieve the status and transcript of completed voice calls after they leave the in-memory manager (e.g. after a gateway restart or enough time has passed), from the tool, the gateway, or the CLI — instead of a dead-end { found: false }.

Evidence

  • extensions/voice-call/index.test.ts: two regression tests — newest snapshot wins over an older ringing record; { found: false } when absent.
  • extensions/voice-call/src/cli.test.ts: two integration tests drive the real voicecall status --call-id ... --json command with the gateway unavailable (ECONNREFUSED) and an evicted call — asserting the CLI fallback resolves the newest persisted snapshot (state: completed) and reports { found: false } when neither active nor persisted. This exercises the actual CLI action end-to-end (only the gateway transport and the in-memory manager are stubbed).
  • pnpm test:extension voice-call: index.test.ts 41/41 and cli.test.ts 10/10 pass. The full extension suite only has pre-existing Windows EPERM teardown flakes in src/manager/events.test.ts (temp-dir fs.rmSync), unrelated to this change.

🤖 AI-assisted. Generated with Claude Code.

Closes #96586

@openclaw-barnacle openclaw-barnacle Bot added channel: voice-call Channel integration: voice-call size: S labels Jul 4, 2026
@clawsweeper

clawsweeper Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 5, 2026, 2:51 PM ET / 18:51 UTC.

Summary
The branch adds an active-first persisted-store fallback for voice-call status lookups across gateway, tool, legacy tool, and CLI paths, plus regression tests and a changelog entry.

PR surface: Source +25, Tests +202, Docs +1. Total +228 across 9 files.

Reproducibility: yes. Source inspection shows current main drops terminal calls from active maps while status paths only check those active maps; I did not run a live carrier call in this read-only review, but the PR discussion includes live Gateway proof.

Review metrics: 1 noteworthy metric.

  • Status Lookup Surfaces: 4 changed to persisted fallback. Gateway, tool, legacy tool, and CLI status readers need aligned lookup semantics so completed calls do not disappear after eviction or restart.

Stored data model
Persistent data-model change detected: serialized state: extensions/voice-call/src/manager.restore.test.ts, serialized state: extensions/voice-call/src/manager.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #96586
Summary: This PR is the active candidate fix for the persisted voice-call status miss tracked by the canonical issue; older same-root PRs are either stale, closed, or less complete, while the redaction PR is adjacent but distinct.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Remove the CHANGELOG.md line added for this PR.

Risk before merge

  • [P1] The PR intentionally bridges active in-memory status lookups to retained persisted call records; preserving active-first and id-precedence semantics is important to avoid stale or mis-associated voice-call state.
  • [P1] The only concrete cleanup blocker I found is release-process hygiene: the PR still edits release-owned CHANGELOG.md.

Maintainer options:

  1. Land Active-First Fallback (recommended)
    Accept the controlled session-state risk because the PR preserves active-call precedence, internal-id precedence, newest retained snapshots, and has focused plus live proof.
  2. Pause For Transcript API Direction
    If maintainers want transcript retrieval bundled with this work, pause and define a separate privileged history API instead of stretching status lookup.

Next step before merge

  • [P2] A repair worker can mechanically remove the release-owned changelog line without touching the voice-call runtime or tests.

Security
Cleared: The diff uses existing voice-call persistence and does not add dependencies, workflows, permissions, downloads, package-resolution changes, or new secret handling.

Review findings

  • [P3] Drop the release-owned changelog entry — CHANGELOG.md:23
Review details

Best possible solution:

Keep the centralized active-first retained-store fallback and focused tests, remove the release-owned changelog edit, and let the linked issue close after this PR merges.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main drops terminal calls from active maps while status paths only check those active maps; I did not run a live carrier call in this read-only review, but the PR discussion includes live Gateway proof.

Is this the best way to solve the issue?

Yes. Centralizing an active-first retained-store lookup at the manager/store boundary is the narrowest maintainable fix for the status miss; the remaining issue is release-process cleanup, not runtime design.

Full review comments:

  • [P3] Drop the release-owned changelog entry — CHANGELOG.md:23
    OpenClaw release notes are generated by the release flow, and this PR still adds a CHANGELOG.md entry at this line. Remove it and keep release-note context in the PR body or squash message so normal feature work does not hand-edit the changelog.
    Confidence: 0.91

Overall correctness: patch is correct
Overall confidence: 0.87

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 3f380635f59b.

Label changes

Label justifications:

  • P2: This is a focused voice-call bug fix for completed-call status visibility with limited blast radius but real agent/operator impact.
  • merge-risk: 🚨 session-state: The diff changes how voice-call status resolves active versus persisted call state, so stale or mis-associated call records are the main merge risk.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): Maintainer comments and labels show live Gateway mock-provider proof plus Testbox/prepare evidence for the changed status path at the reviewed head.
  • proof: sufficient: Contributor real behavior proof is sufficient. Maintainer comments and labels show live Gateway mock-provider proof plus Testbox/prepare evidence for the changed status path at the reviewed head.
Evidence reviewed

PR surface:

Source +25, Tests +202, Docs +1. Total +228 across 9 files.

View PR surface stats
Area Files Added Removed Net
Source 4 43 18 +25
Tests 4 208 6 +202
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 9 252 24 +228

Acceptance criteria:

  • [P1] git diff --check.

What I checked:

Likely related people:

  • steipete: Recent GitHub path history shows repeated voice-call manager/store and SQLite persistence work, and this PR head's maintainer fixup centralizes the persisted status lookup. (role: recent area contributor and maintainer fixup author; confidence: high; commits: 5c82305af476, e5c61383e53e, 3ff86f335020; files: extensions/voice-call/src/manager.ts, extensions/voice-call/src/manager/store.ts, extensions/voice-call/index.ts)
  • eleqtrizit: Merged the read-scoped voice-call status DTO/redaction change that defines the status response boundary this PR preserves while changing lookup behavior. (role: adjacent status-boundary contributor; confidence: medium; commits: 825aafac577a; files: extensions/voice-call/index.ts, extensions/voice-call/index.test.ts)
  • Takhoffman: Recent voice-call store history includes replay/dedupe work adjacent to retained event ordering and restore semantics. (role: adjacent voice-call persistence contributor; confidence: low; commits: 6504087b97ea; files: extensions/voice-call/src/manager/store.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (9 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-04T09:58:04.578Z sha 8a648d2 :: needs real behavior proof before merge. :: [P2] Search retained records instead of only the last 100 events | [P2] Use the full persisted lookup in the CLI fallback too
  • reviewed 2026-07-04T11:57:25.577Z sha 8a648d2 :: needs real behavior proof before merge. :: [P2] Search retained records instead of only the last 100 events | [P2] Use the full persisted lookup in the CLI fallback too
  • reviewed 2026-07-05T17:08:50.980Z sha 5028336 :: needs real behavior proof before merge. :: [P3] Drop the release-owned changelog entry
  • reviewed 2026-07-05T17:14:52.325Z sha 5028336 :: needs real behavior proof before merge. :: [P3] Drop the release-owned changelog entry
  • reviewed 2026-07-05T17:57:00.903Z sha da691d0 :: needs changes before merge. :: [P3] Drop the release-owned changelog entry
  • reviewed 2026-07-05T18:11:21.366Z sha 47c3ba8 :: needs changes before merge. :: [P3] Drop the release-owned changelog entry
  • reviewed 2026-07-05T18:25:41.946Z sha fc22538 :: needs changes before merge. :: [P3] Drop the release-owned changelog entry
  • reviewed 2026-07-05T18:45:51.881Z sha 5c82305 :: needs changes before merge. :: [P3] Drop the release-owned changelog entry

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jul 4, 2026
@Darren2030
Darren2030 force-pushed the claude/96586-voicecall-status-persisted-fallback branch from 9558d31 to f39060a Compare July 4, 2026 04:34
@Darren2030

Copy link
Copy Markdown
Contributor Author

Addressed the review feedback:

  • Align CLI Status Before Merge (P2): The local voicecall status gateway-unavailable fallback now resolves persisted calls too — getCall(id) || getCallByProviderCallId(id), then newest persisted snapshot via getCallHistory(100).toReversed().find(...). All four status readers (gateway method, tool get_status, legacy status mode, CLI fallback) now agree.
  • Real behavior proof (P1): Added integration tests in src/cli.test.ts that drive the real voicecall status --call-id … --json command with the gateway unavailable (ECONNREFUSED) and an evicted call — asserting the newest persisted snapshot (state: completed) is returned and { found: false } when absent. This exercises the actual CLI action end-to-end (only the gateway transport + in-memory manager are stubbed).
  • PR body updated with the fourth site and the CLI evidence.

pnpm test:extension voice-call: index.test.ts 41/41, cli.test.ts 10/10.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@steipete steipete self-assigned this Jul 5, 2026
@steipete
steipete force-pushed the claude/96586-voicecall-status-persisted-fallback branch from 8a648d2 to 5028336 Compare July 5, 2026 17:03
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Maintainer fixup and exact-head proof complete at 5028336d34455dd1543fcbd3461a09e69d84f521.

  • Refactored status resolution to keep active calls as the fast path and put the full retained-store fallback at the manager/store boundary. Internal ids retain precedence over provider ids, and the newest persisted snapshot wins.
  • Testbox lease tbx_01kwsjvbkm7qwr8b5jdbsn10qg: pnpm test extensions/voice-call/index.test.ts extensions/voice-call/src/cli.test.ts extensions/voice-call/src/manager/store.test.ts extensions/voice-call/src/manager.restore.test.ts — 70 passed.
  • Testbox: pnpm check:changed — passed.
  • Live authenticated Gateway proof with the mock provider: initiate, end, active-state eviction, then voicecall status --call-id; the persisted terminal hangup-bot record was returned.
  • Fresh Codex autoreview: no accepted/actionable findings.
  • Exact-head hosted CI/Testbox: run 28748296942 — passed; scripts/pr prepare-run 99797 completed.

No known proof gaps for this status-only fix. Transcript retrieval remains a separate product/API concern.

@steipete
steipete force-pushed the claude/96586-voicecall-status-persisted-fallback branch from 5028336 to da691d0 Compare July 5, 2026 17:45
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jul 5, 2026
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Exact-head follow-up after the main resync: da691d0514e5f6db02b3371bc243b9b1c5bb57f4 is the reviewed PR head.

  • Hosted exact-head CI/Testbox: run 28749447666, fully green.
  • Maintainer prepare gate: OPENCLAW_TESTBOX=1 scripts/pr prepare-run 99797, passed at the same SHA.
  • The focused 70-test voice-call suite, changed gate, and authenticated live Gateway mock-provider lifecycle proof from the earlier land-ready report remain unchanged by the main-only resync.

Land-ready at the exact reviewed head.

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 5, 2026
@steipete
steipete force-pushed the claude/96586-voicecall-status-persisted-fallback branch from da691d0 to 47c3ba8 Compare July 5, 2026 17:58
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Exact-head land-ready recheck for 47c3ba8aeec6c6b90890a6f8b59d2e3568199643:

Known gaps: none for the changed surface.

@steipete
steipete force-pushed the claude/96586-voicecall-status-persisted-fallback branch 3 times, most recently from 3d175b4 to 5c82305 Compare July 5, 2026 18:41
Darren2030 and others added 3 commits July 5, 2026 19:53
…status misses

get_status, the legacy status mode, and the voicecall.status gateway method
only consulted the in-memory call manager. Once a call was evicted (finalize,
gateway restart, or max-duration expiry) they reported { found: false } even
though the full record remained on disk. Fall back to the persisted call
history and resolve the NEWEST matching snapshot — history is oldest-first, so
a forward find() returns a stale record (the regression in the prior attempt).

Closes openclaw#96586

Co-Authored-By: Claude Fable 5 <[email protected]>
Avoids the typescript(unbound-method) lint rule that flags referencing a
typed method (`runtimeStub.manager.getCallHistory`) as an unbound value.
Bracket access matches the existing mock-assertion pattern in this file
(e.g. `runtimeStub.manager["sendDtmf"]`).

Co-Authored-By: Claude Fable 5 <[email protected]>
Darren2030 and others added 2 commits July 5, 2026 19:53
The local CLI `voicecall status` gateway-unavailable fallback only consulted
the in-memory manager, so a completed/evicted call still returned
{ found: false } even though the gateway/tool/legacy status paths now fall
back to the persisted store. Align this fourth status reader: consult
getCallByProviderCallId in addition to getCall, and on an active miss resolve
the NEWEST matching persisted snapshot via getCallHistory(100) +
toReversed().find(...) (history is oldest-first), mirroring the gateway/tool
paths. Return shape is unchanged.

Per review on openclaw#96586 (align CLI status before merge).

Co-Authored-By: Claude Fable 5 <[email protected]>
@steipete
steipete force-pushed the claude/96586-voicecall-status-persisted-fallback branch from 5c82305 to 9db0aab Compare July 5, 2026 18:53
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Exact-head land-ready recheck for 9db0aab92ce340ff975f6c6dce609fa2ac78b346:

Known gaps: none for the changed surface.

@steipete
steipete merged commit 39b5bf3 into openclaw:main Jul 5, 2026
96 checks passed
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
…status misses (openclaw#99797)

* fix(voice-call): resolve completed calls from the persisted store on status misses

get_status, the legacy status mode, and the voicecall.status gateway method
only consulted the in-memory call manager. Once a call was evicted (finalize,
gateway restart, or max-duration expiry) they reported { found: false } even
though the full record remained on disk. Fall back to the persisted call
history and resolve the NEWEST matching snapshot — history is oldest-first, so
a forward find() returns a stale record (the regression in the prior attempt).

Closes openclaw#96586

Co-Authored-By: Claude Fable 5 <[email protected]>

* test(voice-call): use bracket access for mocked getCallHistory assertion

Avoids the typescript(unbound-method) lint rule that flags referencing a
typed method (`runtimeStub.manager.getCallHistory`) as an unbound value.
Bracket access matches the existing mock-assertion pattern in this file
(e.g. `runtimeStub.manager["sendDtmf"]`).

Co-Authored-By: Claude Fable 5 <[email protected]>

* ci: re-trigger QA Smoke (transient build-OOM, also failing main run 28695162780)

* fix(voice-call): resolve persisted calls in the CLI status fallback too

The local CLI `voicecall status` gateway-unavailable fallback only consulted
the in-memory manager, so a completed/evicted call still returned
{ found: false } even though the gateway/tool/legacy status paths now fall
back to the persisted store. Align this fourth status reader: consult
getCallByProviderCallId in addition to getCall, and on an active miss resolve
the NEWEST matching persisted snapshot via getCallHistory(100) +
toReversed().find(...) (history is oldest-first), mirroring the gateway/tool
paths. Return shape is unchanged.

Per review on openclaw#96586 (align CLI status before merge).

Co-Authored-By: Claude Fable 5 <[email protected]>

* refactor(voice-call): centralize persisted status lookup

Co-authored-by: 曾文锋0668000834 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: voice-call Channel integration: voice-call merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[voice-call] get_status returns found:false for completed calls once evicted from in-memory manager — no fallback to persisted call store

2 participants