Skip to content

fix(dictation): stop deriving fallback target IDs from mutable placeholder text#508

Merged
rosscado merged 2 commits into
mainfrom
fix/507-dictation-target-key
Jul 5, 2026
Merged

fix(dictation): stop deriving fallback target IDs from mutable placeholder text#508
rosscado merged 2 commits into
mainfrom
fix/507-dictation-target-key

Conversation

@rosscado

@rosscado rosscado commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • getTargetElementId()'s fallback identifier for id-less dictation targets baked in the element's placeholder attribute — but UniversalDictationModule itself rewrites that placeholder mid-session (e.g. to "Recording...") to show dictation progress, so the key used to register a target's audio/refinement state drifts from the key later used to look it up.
  • This makes contextual refinement (the second phase of dual-phase transcription) silently no-op on any field without a stable id — reproduced live on x.com/i/grok's "Ask anything" composer while scoping baseline universal-dictation support for Grok. The local test fixture never caught this because all its fields have stable ids.
  • Fix: cache a per-element fallback ID in a WeakMap, generated once and independent of any later attribute mutation.

Test plan

  • Added a fail-first regression test (DictationMachine-Refinement.spec.ts, "Target ID Stability (issue Dictation contextual refinement silently fails on any id-less field (target key includes mutable placeholder text) #507)") that mutates an id-less field's placeholder between segment capture and refinement; confirmed it reproduces the exact "No element found for pending refinement target" warning before the fix, and passes after.
  • Updated an existing test that had encoded the old (buggy) placeholder-based key format as expected behavior.
  • npm test green: tsc --noEmit, Jest (2/2), Vitest (205 files / 1795 tests, 1 pre-existing skip).

Fixes #507

🤖 Generated with Claude Code

https://claude.ai/code/session_01T4uuEsKVySbRV9XRQa2ebc

rosscado and others added 2 commits July 5, 2026 18:59
…older text

UniversalDictationModule rewrites a field's placeholder attribute during
recording (e.g. to "Recording..."), but getTargetElementId()'s fallback key
for id-less elements baked the placeholder text in. That desyncs the key
between when a target is registered and when contextual refinement looks
it up later, so refinement silently no-ops with a "No element found for
pending refinement target" warning on any id-less field — reproduced live
on x.com/i/grok's composer while scoping baseline Grok dictation support.

Cache a stable per-element fallback ID in a WeakMap instead, so it survives
attribute mutations for the life of the element.

Fixes #507

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4uuEsKVySbRV9XRQa2ebc
Per review feedback on #508: document that the fix assumes an element's
id-presence doesn't change mid-session, so a future refactor doesn't
silently reintroduce the same class of key-drift bug.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T4uuEsKVySbRV9XRQa2ebc
@rosscado

rosscado commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the two review suggestions:

  • Added a code comment on getTargetElementId() documenting the id-stability assumption (an element's id-presence must not change mid-session, or the same key-drift bug could recur).
  • Noting here for the record: this fix also closes a pre-existing latent collision — two structurally-identical id-less elements (e.g. two blank <textarea>s with no class/name) previously mapped to the same fallback key under the old placeholder-based scheme; the counter suffix now gives each a distinct key. Side benefit, not the primary fix.

@rosscado rosscado merged commit 1f3521b into main Jul 5, 2026
2 checks passed
@rosscado rosscado deleted the fix/507-dictation-target-key branch July 5, 2026 18:14
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.

Dictation contextual refinement silently fails on any id-less field (target key includes mutable placeholder text)

1 participant