feat: usage rows of a linked workspace

RA
15h ago
+1106-143

Closes #1510

Stacked on #1509 (the link lifecycle); review the two commits above it.

What

The rows that say how a linked workspace is used, per the shared event contract.

  • The rows the event contract names carry workspace_id. Each prompt turn resolves the project's local binding (no network) and passes it explicitly: session_start and session_end, first_prompt_sent and first_job_completed, task_classified, task_outcome_signal and the loop's other outcome rows; tool call and failure rows through the tool context (batch's inner tools included); skill_used; memory_injection and memory_operation through the injection context; the workspace rows carry their own ids. Nothing is stamped ambiently. Every other row (generation, compaction, SQL fingerprints, file-time, suggestions, native warehouse, MCP, permissions) joins through session_id.
  • Workspace values where the event already existed: skill_used.skill_source gains workspace (skills synced into the managed _workspace folder); memory_injection.scopes_used gains workspace and a workspace_blocks count when blocks came from the workspace's cloud memory; tool_call gains via_workspace on calls to the workspace's MCP tools; skill_published carries the workspace id.
  • Per-session use counters feed session_end (workspace_skills_used, workspace_documents_used, workspace_memory_blocks, workspace_integration_calls) and task_outcome_signal.workspace_context_used.
  • New events: starter_shown when the post-link starter is served (what the workspace provides, as counts); workspace_memory_contributed on every block written back to the workspace; workspace_sync_failed when a kind's sync status flips to error, with a reason class.

Not here: workspace_document_used (no document read path exists yet to hook), the session-start counts of what the workspace provides (they need the service; the starter row carries them when served), and a usage-limit event (which limits count is undefined).

Why

Linking tells the funnel a workspace reached the CLI; these rows tell it whether the workspace is then used, and what it gives back.

Verification

  • New tests: the stamping (bound and unbound sessions, a row's own id wins), the per-session counters, the _workspace skill source, a memory injection with a workspace block (scope and count), the write-back event, the sync-failure event and its reason classifier, the starter event's counts.
  • Workspace, memory, telemetry and tool suites pass; tsgo --noEmit, oxlint and the marker guard clean. Two unrelated timing flakes in the wider suites (session prompt, tool registry) pass alone on this branch and on the base.

šŸ¤– Generated with Claude Code

https://claude.ai/code/session_011AhtJPr3nmT1Po92ZQk4VE