Skip to content

fix(canvas-sync): mirror voiceCapable+voiceId in pushCanvasStateToCloud#1331

Merged
itskai-dev merged 2 commits into
mainfrom
claude/voice-capable-truth-seam-second-writer
May 4, 2026
Merged

fix(canvas-sync): mirror voiceCapable+voiceId in pushCanvasStateToCloud#1331
itskai-dev merged 2 commits into
mainfrom
claude/voice-capable-truth-seam-second-writer

Conversation

@itskai-dev

Copy link
Copy Markdown
Collaborator

Summary

Two node writers POST to /api/hosts/:id/canvas:

The cloud POST handler at apps/api/src/host-canvas-state-routes.ts:89-99 writes payload: agentState as object — full replace, not merge. So the 5s writer was clobbering voiceCapable/voiceId set by the 30s syncCanvas. Compass on canonical was observed flipping voiceCapable true → false → true on each cycle.

Patch

Extend the 5s writer to mirror writer #1's voice derivation from the same agent_config.settings.voice source. Both writers now agree on payload shape, so the later writer preserves what the earlier one set.

13 lines, one file. Build clean.

Why this and not a cloud-side merge

Cloud-side merge in the POST handler would also fix it, but (c) every writer sends canonical shape is the right invariant for now — it stays explicit about the source of truth for each field. Flagged the structural fragility (two writers + full-replace POST) to @kai separately for a follow-up lane.

Unblocks

reflectt-cloud PR #3230 — speak visibility V0. Once this merges and canonical rolls, the speak proof spec can prove compass lit / others honestly blocked.

Test plan

  • Build clean (verified locally — npm run build passes)
  • After merge + canonical roll, GET /api/hosts/{canonical}/canvas returns compass.voiceCapable=true, voiceId='af_sarah' and stays stable across multiple polls (not just first sync)
  • Re-run apps/web/e2e/_speak-row-proof.spec.ts against PR #3230 Vercel preview — passes 4-bar test

itskai-dev and others added 2 commits May 4, 2026 10:47
…StateToCloud

Two node writers POST to /api/hosts/:id/canvas:
  - src/cloud.ts:1558 syncCanvas (30s cadence) — sets voiceCapable
    via PR #1330 truth seam from agent_config.settings.voice
  - src/server.ts:13151 pushCanvasStateToCloud (5s cadence) — sent
    only {state, task, displayName, identityColor, avatar}

The cloud POST handler does `payload: agentState as object` (full
replace, not merge). The 5s writer was clobbering voiceCapable/voiceId
set by the 30s syncCanvas. Compass observed flipping voiceCapable
true→false→true on each cycle.

Patch: extend the 5s writer to mirror writer #1's voice derivation
from the same agent_config.settings.voice source. Both writers now
agree on payload shape so the later one preserves what the earlier
set.

Unblocks reflectt-cloud PR #3230 speak V0 proof.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
task-1777140469973-770cy4yma — speak visibility V0 truth-seam
follow-up unblocking pushCanvasStateToCloud writer #2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@itskai-dev
itskai-dev merged commit ee5afee into main May 4, 2026
11 checks passed
@itskai-dev
itskai-dev deleted the claude/voice-capable-truth-seam-second-writer branch May 4, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant