0.5.2
A single-fix cohort, shipped for the first downstream consumer that hit it in production forensics. The wire vocabulary is untouched — AGJSON_VERSION stays 1.0.0-draft.2.
createClaudeNormalizer({ threadId })
The Claude Agent SDK wire has no thread concept — only session_id — so the claude facet has always relabeled that id as the AgJSON threadId, a placeholder in the same spirit as the openai/vercel facets’ fixed labels. That placeholder is fine for self-contained streams, but it leaks: a consumer that persists events verbatim under its own thread identity ends up with mid-stream rows keyed by the SDK’s session id while its session records carry the real thread id (guuey#415, where the mismatch confounded an identity investigation).
The factory now accepts an options object with threadId: the runtime that owns the real partition root stamps it at construction, and every emitted entity — messages, synthesized turn.starts, notice rows, denial records — carries one id everywhere. Per SPEC §3, threadId is the partition root a key-value persistence layer writes by; the layer that owns that identity is the caller, not the wire.
Absent the option, the legacy session_id relabeling stands unchanged — recorded cassettes and existing consumers are byte-identical. Synthesized turn ids continue to embed the session id as opaque identifiers; that is deliberate and not part of this change.