1. Define a canonical fact table for Netflix member playback telemetry.
Specify the row grain, stable event identity, keys, and minimum columns needed to calculate total watch time by title and day across devices while remaining correct under client retries. Distinguish member, profile, device, session, content, event time, ingestion time, duration, schema version, and correction metadata, and state how a deterministic current view relates to immutable source history.
I would keep one current fact row per logical event_id. Client retries reuse that ID, while immutable history stores every delivery. Corrections are selected deterministically, and watch time sums duration_ms for ACTIVE rows by content_id and the UTC date of event_time_utc.
See the Code while reading this explanation.
The goal is to count viewing time correctly even when the same viewing record arrives more than once. Each real playback event needs one stable identity, while every received copy should still be kept for traceability. Later corrections must change the current meaning without deleting the original history. The reporting view should contain only one selected version of each playback event. Daily totals must use when playback actually happened, not when the data arrived, so retries and late deliveries do not move viewing time to another day or count the same playback twice.
- Should every retry of the same logical playback event reuse the same event_id?
- Which event_status values exist, and should only ACTIVE events contribute to watch time?
- Is event_time_utc already normalized to UTC before it reaches this model?
- Are member_id, profile_id, device_id, session_id, and content_id stable upstream identifiers?
Start with the grain. The canonical fact, fact_playback_events, has one current row per logical playback event_id after retry deduplication and correction selection. event_id is the primary key of this current view. A retry of the same logical event reuses the same event_id. Playback on another device is a different logical playback event and therefore gets a different event_id.
Keep immutable source history separately in fact_playback_events_history. Its grain is one row per received delivery. delivery_id identifies a particular immutable delivery, while event_id identifies the logical playback event. Multiple history rows can therefore share one event_id when the client retries or when a corrected version is delivered. History is append-only and is not deleted.
The canonical current fact contains event_id, member_id, profile_id, device_id, session_id, content_id, event_time_utc, ingestion_time_utc, duration_ms, schema_version, correction_version, and event_status. member_id identifies the member, profile_id the viewing profile, device_id the playback device, session_id the playback session, and content_id the title or content. event_time_utc records when playback occurred. ingestion_time_utc records when that delivery reached the data platform. duration_ms is the watch-time measure. schema_version identifies the event schema version. correction_version orders corrections of the same logical event. event_status controls whether the selected event contributes to the metric.
Build the current view deterministically from immutable history. For each event_id, choose the row with the highest correction_version. If rows still tie, choose the latest ingestion_time_utc. If they still tie, use delivery_id descending as the final deterministic tie-break. The current fact is therefore a reproducible derived view that can be rebuilt from immutable history.
For total watch time, query the canonical current fact rather than immutable delivery history. Filter to event_status = 'ACTIVE', group by content_id and DATE(event_time_utc), and sum duration_ms. The result grain is one row per content_id and UTC day. Retries do not inflate the metric because only one current row exists per logical event_id.
No specific database engine was named. The SQL therefore follows the warehouse-style syntax shown in the approved diagram and assumes event_time_utc is stored as a UTC timestamp for DATE(event_time_utc) to represent the UTC playback day.
- Declare the canonical current fact grain as one row per logical event_id.
- Require retries of the same logical playback event to reuse event_id.
- Append every received delivery to immutable history with its own delivery_id.
- Keep correction_version and event_status with each delivered version.
- For each event_id, select correction_version descending, then ingestion_time_utc descending, then delivery_id descending.
- Expose that selected row as the canonical current fact.
- For watch-time reporting, filter to event_status = 'ACTIVE', group by content_id and the UTC date of event_time_utc, and sum duration_ms.
Immutable history uses more storage because it keeps every delivery, including retries and corrections. Rebuilding the current fact requires grouping or ordering history rows by event_id to select one row for each logical playback event. The current fact is smaller because it has one selected row per event_id. Daily reporting then filters ACTIVE rows and aggregates duration. The tradeoff is extra history storage and transformation work in exchange for retry safety, auditability, deterministic corrections, and reproducible watch-time metrics.
-- Read the canonical current fact so retry deliveries are not double-counted.
SELECT
content_id,
-- event_time_utc represents when playback occurred and defines the UTC reporting day.
DATE(event_time_utc) AS day_utc,
-- duration_ms is additive across the selected logical playback events.
SUM(duration_ms) AS total_watch_ms
FROM
fact_playback_events
-- Only ACTIVE current events contribute watch time.
WHERE
event_status = 'ACTIVE'
-- Result grain: one row per content_id and UTC playback day.
GROUP BY
content_id,
DATE(event_time_utc);This tests whether the candidate can declare a precise fact-table grain, separate logical playback identity from physical deliveries, handle duplicate client retries safely, model corrections without losing immutable history, distinguish event time from ingestion time, and define a deterministic analytical view that produces correct watch-time totals across devices.
Using ingestion_time_utc instead of event_time_utc for the reporting day can assign late-arriving playback to the wrong day. Aggregating immutable history directly can double-count client retries. Giving every retry a new event_id prevents correct deduplication. Overwriting history removes auditability and makes reconstruction harder. Selecting a correction without deterministic ordering can produce inconsistent rebuilds. Summing non-ACTIVE current rows can inflate watch time. Another mistake is treating playback on another device as a retry of the same logical event.
Lead with the grain and identity rule: one current row per logical event_id, while every delivery remains in immutable history. Then explain the deterministic correction order and finish with the metric rule: sum ACTIVE duration_ms by content_id and UTC event date.









