Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ SELECT
lower(trim(email)) AS email,
toDate(date) AS day,
'chatgpt' AS tool,
'ChatGPT' AS tool_label,
'chat' AS surface,
'Chat' AS surface_label,
-- chat is not session-bounded in the API → session_count NULL
CAST(NULL AS Nullable(UInt32)) AS session_count,
CAST(NULL AS Nullable(UInt32)) AS conversation_count,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ SELECT
CAST(NULL AS Nullable(String)) AS api_key_id,
toDate(date) AS day,
'codex' AS tool,
'Codex' AS tool_label,
-- Codex threads ≈ coding sessions. Non-nullable UInt32 per contract.
toUInt32(coalesce(toUInt32OrNull(toString(n_threads)), 0)) AS session_count,
toUInt32OrNull(toString(n_threads)) AS conversation_count,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ SELECT
CASE WHEN u.actor_type = 'api_actor' THEN k.api_key_id END AS api_key_id,
u.day,
'claude_code' AS tool,
'Claude Code' AS tool_label,
toUInt32(u.sessions_sum) AS session_count,
toUInt32OrNull(toString(u.sessions_sum)) AS conversation_count,
toUInt32(u.lines_added_sum) AS lines_added,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ chat AS (
email,
day,
'claude' AS tool,
'Claude' AS tool_label,
'chat' AS surface,
'Chat' AS surface_label,
-- chat is not session-bounded in the API → session_count NULL
CAST(NULL AS Nullable(UInt32)) AS session_count,
toUInt32OrNull(toString(chat_conversation_count)) AS conversation_count,
Expand Down Expand Up @@ -140,9 +138,7 @@ excel AS (
email,
day,
'claude' AS tool,
'Claude' AS tool_label,
'excel' AS surface,
'Excel' AS surface_label,
toUInt32OrNull(toString(excel_session_count)) AS session_count,
CAST(NULL AS Nullable(UInt32)) AS conversation_count,
toUInt32OrNull(toString(excel_message_count)) AS message_count,
Expand Down Expand Up @@ -177,9 +173,7 @@ powerpoint AS (
email,
day,
'claude' AS tool,
'Claude' AS tool_label,
'powerpoint' AS surface,
'PowerPoint' AS surface_label,
toUInt32OrNull(toString(powerpoint_session_count)) AS session_count,
CAST(NULL AS Nullable(UInt32)) AS conversation_count,
toUInt32OrNull(toString(powerpoint_message_count)) AS message_count,
Expand Down Expand Up @@ -214,9 +208,7 @@ cowork AS (
email,
day,
'claude' AS tool,
'Claude' AS tool_label,
'cowork' AS surface,
'Cowork' AS surface_label,
toUInt32OrNull(toString(cowork_session_count)) AS session_count,
CAST(NULL AS Nullable(UInt32)) AS conversation_count,
toUInt32OrNull(toString(cowork_message_count)) AS message_count,
Expand Down Expand Up @@ -259,9 +251,7 @@ cross_surface AS (
email,
day,
'claude' AS tool,
'Claude' AS tool_label,
'cross' AS surface,
'Cross' AS surface_label,
CAST(NULL AS Nullable(UInt32)) AS session_count,
CAST(NULL AS Nullable(UInt32)) AS conversation_count,
CAST(NULL AS Nullable(UInt32)) AS message_count,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ SELECT
CAST(NULL AS Nullable(String)) AS api_key_id,
toDate(parseDateTimeBestEffortOrNull(date)) AS day,
'claude_code' AS tool,
'Claude Code' AS tool_label,
toUInt32(coalesce(code_session_count, 0)) AS session_count,
toUInt32OrNull(toString(code_session_count)) AS conversation_count,
toUInt32(coalesce(code_lines_added, 0)) AS lines_added,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ SELECT
CAST(NULL AS Nullable(String)) AS api_key_id,
toDate(metric_date) AS day,
'claude_code' AS tool,
'Claude Code' AS tool_label,
toUInt32(coalesce(total_sessions, 0)) AS session_count,
toUInt32OrNull(toString(total_sessions)) AS conversation_count,
toUInt32(coalesce(total_lines_accepted, 0)) AS lines_added,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ SELECT
CAST(NULL AS Nullable(String)) AS api_key_id,
toDate(fromUnixTimestamp64Milli(CAST(date AS Int64))) AS day,
'cursor' AS tool,
'Cursor' AS tool_label,
toUInt32(1) AS session_count,
CAST(NULL AS Nullable(UInt32)) AS conversation_count,
toUInt32(coalesce(acceptedLinesAdded, 0)) AS lines_added,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ SELECT
CAST(NULL AS Nullable(String)) AS api_key_id,
toDate(parseDateTimeBestEffortOrNull(m.day)) AS day,
'copilot' AS tool,
'GitHub Copilot' AS tool_label,
-- session_count: Copilot doesn't expose a per-day session counter;
-- presence of an activity row implies at least one active session.
-- Match Cursor's convention: 1 per active day.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ WITH src AS (
'annualrevenue', coalesce(toString(properties_annualrevenue), ''),
'archived', toString(coalesce(archived, false))
)) AS metadata,
-- Envelope parity with salesforce__crm_* (no HubSpot custom-fields blob).
'{}' AS custom_fields,
createdAt AS created_at,
updatedAt AS updated_at,
data_source,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ WITH calls AS (
'direction', coalesce(toString(properties_hs_call_direction), ''),
'archived', toString(coalesce(archived, false))
)) AS metadata,
-- Envelope parity with salesforce__crm_* (no HubSpot custom-fields blob).
'{}' AS custom_fields,
createdAt AS created_at,
data_source,
greatest(
Expand Down Expand Up @@ -112,6 +114,7 @@ emails AS (
'direction', coalesce(toString(properties_hs_email_direction), ''),
'archived', toString(coalesce(archived, false))
)) AS metadata,
'{}' AS custom_fields,
createdAt AS created_at,
data_source,
greatest(
Expand Down Expand Up @@ -167,6 +170,7 @@ meetings AS (
'location', coalesce(toString(properties_hs_meeting_location), ''),
'archived', toString(coalesce(archived, false))
)) AS metadata,
'{}' AS custom_fields,
createdAt AS created_at,
data_source,
coalesce(
Expand Down Expand Up @@ -208,6 +212,7 @@ tasks AS (
'type', coalesce(toString(properties_hs_task_type), ''),
'archived', toString(coalesce(archived, false))
)) AS metadata,
'{}' AS custom_fields,
createdAt AS created_at,
data_source,
greatest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ WITH src AS (
'hs_analytics_source', coalesce(toString(properties_hs_analytics_source), ''),
'archived', toString(coalesce(archived, false))
)) AS metadata,
-- Envelope parity with salesforce__crm_* (no HubSpot custom-fields blob).
'{}' AS custom_fields,
createdAt AS created_at,
updatedAt AS updated_at,
data_source,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ WITH src AS (
'deal_type', coalesce(toString(properties_dealtype), ''),
'archived', toString(coalesce(archived, false))
)) AS metadata,
-- Envelope parity with salesforce__crm_* (no HubSpot custom-fields blob).
'{}' AS custom_fields,
createdAt AS created_at,
updatedAt AS updated_at,
data_source,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ WITH src AS (
'userId', coalesce(toString(userId), ''),
'archived', toString(coalesce(archived, false))
)) AS metadata,
-- Envelope parity with salesforce__crm_* (no HubSpot custom-fields blob).
'{}' AS custom_fields,
collected_at,
data_source,
greatest(
Expand Down
27 changes: 27 additions & 0 deletions src/ingestion/dbt/macros/ai_labels.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{# Display labels for the AI `tool` and `surface` dimension codes — static
product vocabulary, same rationale as git_source_label: computed at gold
read time, never denormalized into silver rows. An unmapped code falls
through as itself. #}

{% macro ai_tool_label(tool_expr) %}
multiIf(
{{ tool_expr }} = 'cursor', 'Cursor',
{{ tool_expr }} = 'claude_code', 'Claude Code',
{{ tool_expr }} = 'copilot', 'GitHub Copilot',
{{ tool_expr }} = 'codex', 'Codex',
{{ tool_expr }} = 'claude', 'Claude',
{{ tool_expr }} = 'chatgpt', 'ChatGPT',
{{ tool_expr }}
)
{% endmacro %}

{% macro ai_surface_label(surface_expr) %}
multiIf(
{{ surface_expr }} = 'chat', 'Chat',
{{ surface_expr }} = 'excel', 'Excel',
{{ surface_expr }} = 'powerpoint', 'PowerPoint',
{{ surface_expr }} = 'cowork', 'Cowork',
{{ surface_expr }} = 'cross', 'Cross',
{{ surface_expr }}
)
{% endmacro %}
30 changes: 0 additions & 30 deletions src/ingestion/dbt/tests/ai/assert_ai_class_labels_nonempty.sql

This file was deleted.

24 changes: 13 additions & 11 deletions src/ingestion/gold/ai_metric_observations.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
-- Source measure observations for the unified metrics runtime. Reads only
-- class-contract fields: activity is row existence (the class contract
-- guarantees rows exist only for real activity — see silver/ai/schema.yml),
-- display labels come from tool_label / surface_label, and conversation
-- display labels derive from the tool / surface discriminator codes via the
-- shared vocabulary macros (macros/ai_labels.sql — static product
-- vocabulary, never denormalized into silver rows), and conversation
-- semantics come from data presence (conversation_count is NULL for sources
-- without a conversation concept). Discriminator and label columns are
-- non-null non-empty by the class contract (enforced by silver schema tests);
-- this model consumes them as-is. No vendor-specific columns, tool names, or
-- label mappings may appear in this model. Every measure is emitted through
-- the shape macros in macros/metric_observation_measures.sql; filter
-- predicates may reference only class-contract dimension values.
-- without a conversation concept). Discriminator columns are non-null
-- non-empty by the class contract (enforced by silver schema tests); this
-- model consumes them as-is. No vendor mapping is inlined in this model —
-- labels go through the macros only. Every measure is emitted through the
-- shape macros in macros/metric_observation_measures.sql; filter predicates
-- may reference only class-contract dimension values.

WITH
ai_dev_usage_source AS (
Expand All @@ -24,7 +26,7 @@ ai_dev_usage_source AS (
lower(email) AS entity_id,
day AS metric_date,
CAST(
[tuple('tool', tool, tool_label)]
[tuple('tool', tool, {{ ai_tool_label('tool') }})]
AS Array(Tuple(key String, value String, label Nullable(String)))
) AS tool_dimensions,
conversation_count,
Expand All @@ -44,13 +46,13 @@ ai_assistant_usage_source AS (
day AS metric_date,
surface,
CAST(
[tuple('tool', tool, tool_label)]
[tuple('tool', tool, {{ ai_tool_label('tool') }})]
AS Array(Tuple(key String, value String, label Nullable(String)))
) AS tool_dimensions,
CAST(
[
tuple('tool', tool, tool_label),
tuple('surface', surface, surface_label)
tuple('tool', tool, {{ ai_tool_label('tool') }}),
tuple('surface', surface, {{ ai_surface_label('surface') }})
] AS Array(Tuple(key String, value String, label Nullable(String)))
) AS tool_surface_dimensions,
conversation_count,
Expand Down
12 changes: 11 additions & 1 deletion src/ingestion/gold/collab_metric_observations.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
order_by=['source_key', 'measure_key', 'entity_id', 'metric_date'],
schema='insight',
alias='collab_metric_observations',
tags=['gold']
tags=['gold'],
query_settings={
'max_memory_usage': 1610612736,
'max_threads': 4,
'max_bytes_before_external_group_by': 805306368,
'max_bytes_before_external_sort': 805306368
}
) }}

-- Source measure observations for the unified metrics runtime, collaboration
Expand All @@ -22,6 +28,10 @@
-- (source_key, measure_key, entity_id, metric_date), so single-measure
-- queries read index-pruned ranges rather than the whole relation.
--
-- query_settings bound the CREATE-AS-SELECT for every runner: an
-- over-limit build spills aggregation/sort state to disk instead of
-- failing on the server memory tracker.
--
-- The `tool` dimension value is the `data_source` discriminator with the
-- `insight_` prefix stripped (m365, slack, zoom, zulip_proxy). All Microsoft
-- 365 surfaces (Teams, Outlook, OneDrive, SharePoint) share the m365 tool.
Expand Down
12 changes: 11 additions & 1 deletion src/ingestion/gold/git_metric_observations.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
order_by=['source_key', 'measure_key', 'entity_id', 'metric_date'],
schema='insight',
alias='git_metric_observations',
tags=['gold']
tags=['gold'],
query_settings={
'max_memory_usage': 1610612736,
'max_threads': 4,
'max_bytes_before_external_group_by': 805306368,
'max_bytes_before_external_sort': 805306368
}
) }}

-- Source measure observations for the unified metrics runtime, git family.
Expand All @@ -22,6 +28,10 @@
-- (source_key, measure_key, entity_id, metric_date), so single-measure
-- queries read index-pruned ranges rather than the whole relation.
--
-- query_settings bound the CREATE-AS-SELECT for every runner: an
-- over-limit build spills aggregation/sort state to disk instead of
-- failing on the server memory tracker.
--
-- Grain per measure:
-- day-grain sums: commit_count, code_lines_added, lines_added,
-- pr_created, pr_merged
Expand Down
Loading
Loading