Observability, Quality, Cost & Security
Making the platform reliable, trustworthy, cheap and safe
Data observability & quality
After this you can define what to monitor and how to catch bad data early.
The job description names it directly: build observability, alerting, SLAs/SLOs and operational standards across the platform. In the loop that line becomes a probe - when a column goes null at 3am, do you find out from a dashboard or from an analyst's angry Slack?
Cursor ingests billions of product-telemetry events a day and a slice of that feeds agent and model work. Bad data there is not a cosmetic bug. A silently broken bronze table can poison a gold metric a VP reads or skew a feature an agent learns from. So the interviewer wants a mental model of what can go wrong, not a list of vendor names.
The dimensions you actually monitorfive, not three
Observability for data is usually framed as a small set of dimensions. Name them, then say which ones you'd wire up first for a brand-new platform.
- Dimension
- Freshness
- Question it answers
- Did new data land on time?
- Concrete check at Cursor scale
- Bronze telemetry partition for the current hour exists and is < 15 min late
- Dimension
- Volume
- Question it answers
- Did the right amount arrive?
- Concrete check at Cursor scale
- Event count within ±20% of the same hour last week; zero rows = page
- Dimension
- Schema
- Question it answers
- Did the shape change underneath us?
- Concrete check at Cursor scale
- New/dropped columns, type drift, an enum that grew a value the parser ignores
- Dimension
- Distribution
- Question it answers
- Are the values plausible?
- Concrete check at Cursor scale
- Null rate on
user_id, p99 oflatency_ms, ratio of a category that suddenly flips
- Dimension
- Lineage
- Question it answers
- What breaks if this breaks?
- Concrete check at Cursor scale
- Map from a bronze asset to every silver/gold/serving consumer downstream
| Dimension | Question it answers | Concrete check at Cursor scale |
|---|---|---|
| Freshness | Did new data land on time? | Bronze telemetry partition for the current hour exists and is < 15 min late |
| Volume | Did the right amount arrive? | Event count within ±20% of the same hour last week; zero rows = page |
| Schema | Did the shape change underneath us? | New/dropped columns, type drift, an enum that grew a value the parser ignores |
| Distribution | Are the values plausible? | Null rate on user_id, p99 of latency_ms, ratio of a category that suddenly flips |
| Lineage | What breaks if this breaks? | Map from a bronze asset to every silver/gold/serving consumer downstream |
Freshness and volume catch the obvious outages; schema and distribution catch the quiet corruptions that hurt most.
Two ways to catch bad datainline gates vs. out-of-band watchers
Run in the pipeline: Dagster asset checks, dbt tests, Great Expectations.
Deterministic assertions you already know to make - not_null, unique, accepted range, referential keys.
Can block: a failing check fails the asset and stops propagation.
Run beside the pipeline on a schedule, often statistical or learned.
Catches the unknown unknowns - a slow null-rate creep no one wrote a rule for.
Usually alerts rather than blocks; noisier, needs a feedback loop to stay trusted.
Strong answers use both and say why. Inline tests encode the failures you can predict. Anomaly detection covers the ones you can't - but it earns trust slowly, so you start it in observe-only mode before letting it page anyone.
Two distinct failure classes and you own both. System reliability: did the job run, finish and hit its window? Data quality: is the data the job produced correct? A pipeline can be green - every task succeeded - and still write garbage because an upstream schema changed. Conflating the two is the classic junior tell.
Lineage is impact analysisthe difference between a 5-minute and 5-hour incident
When a bronze table breaks, the first question is who consumes it. Without lineage you find out by getting paged by each downstream owner in turn. With lineage you query the graph, see the eleven silver assets and the one revenue dashboard hanging off it and decide blast radiusHow much breaks if a change goes wrong; the scope of potential damage. in one look.
- Impact analysis
- One broken source resolves to its full downstream set instantly
- Root cause
- A bad gold number traces back up to the exact bronze asset that drifted
- Change safety
- Before you alter a schema, you see everyone who'll feel it
- Trust
- Stakeholders can ask "where did this number come from" and get a real answer
An agent can walk that graph for you. A finance team hit discrepancies in a revenue-recognition booking table that sits downstream of five or six upstream tables plus the jobs running between them. They pointed Cursor at the bad number and it traced the reconciliation issue back up the chain - which tables feed which, which jobs produce which outputs, whether snapshots existed and which PRs changed how each table gets built - walking the whole history to the furthest upstream source.
This is the senior version of root-cause: not just that lineage exists, but using an agent to traverse it across tables, jobs, snapshots and the PRs that changed them.
"We're actually able to trace back the reconciliation issues all the way back to the furthest upstream table using Cursor."
Circuit-breakers: block, don't just alertstop bad data at the silver gate
An alert that fires after corrupt data reached the gold serving layer is a postmortem, not a save. The higher-impact pattern is a circuit-breaker: the quality check sits on the boundary into silver/gold and when it fails, the bad partition does not promote.
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
The quality gate sits on the bronze→silver boundary - fail it and the bad partition never promotes.
- 1Land raw in bronze unconditionally. Never block ingestion; you want the evidence even when it's malformed.
- 2Gate the bronze→silver promotion. Run asset checks before the write commits. On failure, halt that partition and hold the last-good version.
- 3Quarantine, don't drop. Route failing rows to a dead-letter/quarantine table so they're inspectable, not lost.
- 4Page with context. The alert says which check, which partition and what's downstream - so the on-call can act, not investigate from zero.
When asked how you'd guarantee data quality, don't list test types. Lead with the boundary: "I'd put blocking checks on the promotion into the serving layer, quarantine failures and keep the last-good partition live so consumers never read corruption." Then mention inline tests plus out-of-band anomaly detection as the two ways you populate those checks. Designing for containment before detection is the senior signal here.
Takeaway. Monitor five dimensions (freshness, volume, schema, distribution, lineage), keep data quality separate from did-the-job-run reliability and prefer a blocking circuit-breaker at the serving boundary over an alert that arrives after the corruption lands.
Self-check
QEvery task in last night's pipeline succeeded - all green - but the gold revenue table is showing numbers that are clearly wrong. What likely happened and what does this tell you about your monitoring?
SLAs, SLOs and alerting
After this you can operate the platform like a product with reliability targets.
A data platform is a product with internal customers and customers want commitments. The behavioral theme in the JD is explicit: treat the platform as a product. SLAs are how you write that down.
The mistake juniors make is one blanket promise for everything. The mistake of someone who's run a real platform is a tiered promise - because agent-training data and revenue numbers do not deserve the same reliability budget as an analyst's exploratory scratch table.
SLA, SLO, SLI - keep them straightthe vocabulary interviewers check
- SLA
- The promise to the consumer ("gold revenue is fresh by 6am, 99.5% of days")
- SLO
- Your internal target, set tighter than the SLA to leave headroom
- SLI
- The measured signal you compute the SLO from (actual freshness lag in minutes)
- Error budget
- How much you're allowed to miss before it's a stop-the-line problem
Set the SLO stricter than the SLA so a breach of the target is a warning, not yet a broken promise.
Tier datasets by what they feednot everything is tier-1
- Dataset class
- Tier 1 - revenue / agent-training
- Example
- Billing facts, model-feed feature tables
- Freshness target
- Minutes to single-digit hours, completeness near 100%
- On breach
- Page on-call; block promotion of incomplete data
- Dataset class
- Tier 2 - core analytics
- Example
- Daily active users, retention marts
- Freshness target
- By the morning business day
- On breach
- Ticket + Slack to owner; degrade gracefully
- Dataset class
- Tier 3 - exploratory
- Example
- Ad-hoc tables, experiment scratch
- Freshness target
- Best-effort
- On breach
- No paging; visible in a dashboard only
| Dataset class | Example | Freshness target | On breach |
|---|---|---|---|
| Tier 1 - revenue / agent-training | Billing facts, model-feed feature tables | Minutes to single-digit hours, completeness near 100% | Page on-call; block promotion of incomplete data |
| Tier 2 - core analytics | Daily active users, retention marts | By the morning business day | Ticket + Slack to owner; degrade gracefully |
| Tier 3 - exploratory | Ad-hoc tables, experiment scratch | Best-effort | No paging; visible in a dashboard only |
Tiering is also a cost lever - tier-1 freshness is expensive, so you don't buy it for tables nobody depends on.
Alert on symptoms, not just causeswhat the consumer actually feels
"Job failed" is a cause. "The gold table consumers read is now stale past its SLA" is a symptom. You want both, but the symptom alert is the one that maps to a broken promise - and it fires even when the job succeeded but produced nothing.
Dagster run failed, Spark job OOM'd, connector errored.
Tells you what broke in the machinery.
Misses the case where everything ran but the output is wrong or empty.
Gold table freshness lag exceeded its SLO.
Row count for the hour dropped to zero.
Fires on the thing a stakeholder would notice, regardless of cause.
On-call without burning the teamdata on-call is different from service on-call
Data incidents are often slower-burning than a downed API. A late table at 2am rarely needs a human at 2am if the consuming dashboard is read at 8am. Encode that: severity tiers decide who gets paged and when.
- 1Severity-tier every alert. Sev-1 pages immediately (revenue/agent data broken). Sev-3 opens a ticket for business hours.
- 2Route by ownership. The alert goes to the team that owns the asset, not a shared firehose nobody reads.
- 3Dedupe and group. One upstream break should fire one incident, not forty downstream alerts that bury the root cause.
- 4Write the runbook before the incident. Each tier-1 asset has a runbook: how to detect, how to backfill, who to escalate to.
- 5Degrade gracefully. Serve last-good data with a staleness banner rather than a hard failure where you can.
An on-call who's been paged six times for a non-issue will miss the seventh page that matters. Every alert that fires and gets dismissed without action is a bug in your alerting, not a fact of life. Track alert→action rate as a metric and prune anything that's mostly noise.
"I'd tier datasets by what they feed - revenue and agent-training data get minute-level freshness SLAs and paging; exploratory tables get best-effort and a dashboard. Then I report platform reliability as a first-class number to stakeholders each month, so reliability is a shared metric, not a thing they only notice when it breaks."
Takeaway. Tier datasets by what they feed, set SLOs tighter than the SLAs you promise, alert on consumer-facing symptoms (stale table) over machinery causes (job failed) and protect the on-call with severity tiers, dedup and ownership routing.
Self-check
Cost optimization at TB/PB scale
After this you can make billions of events a day economically sustainable.
The JD's recurring trio is scale, reliability, and cost. At billions of events a day, a sloppy storage layout or an always-on cluster isn't a rounding error - it's a line item someone in finance will ask you about.
Cost optimization splits cleanly into two bills: what you pay to store the data and what you pay to compute over it. Treat them separately, because the levers are different and a good answer touches both.
Storage: the small-file problem and friendsobject-store cost and read amplification
- Lever
- Compaction
- Problem it fixes
- Millions of tiny files from streaming writes - slow reads, metadata bloat
- What you actually do
- Periodic OPTIMIZE / compaction to target ~128MB–1GB files
- Lever
- Partitioning
- Problem it fixes
- Every query scans the whole table
- What you actually do
- Partition by a high-selectivity column (usually date/hour) so the engine prunes
- Lever
- Z-ordering / clustering
- Problem it fixes
- Even within a partition, related rows are scattered
- What you actually do
- Cluster on common filter columns so scans skip irrelevant files
- Lever
- Lifecycle / retention
- Problem it fixes
- Raw data accumulating forever in expensive hot storage
- What you actually do
- Expire or tier past the replay window; vacuum old Delta versions
| Lever | Problem it fixes | What you actually do |
|---|---|---|
| Compaction | Millions of tiny files from streaming writes - slow reads, metadata bloat | Periodic OPTIMIZE / compaction to target ~128MB–1GB files |
| Partitioning | Every query scans the whole table | Partition by a high-selectivity column (usually date/hour) so the engine prunes |
| Z-ordering / clustering | Even within a partition, related rows are scattered | Cluster on common filter columns so scans skip irrelevant files |
| Lifecycle / retention | Raw data accumulating forever in expensive hot storage | Expire or tier past the replay window; vacuum old Delta versions |
The small-file problem is the one almost every fast-growing platform hits - streaming ingestion writes constantly and nobody compacts until reads slow to a crawl.
A good partition scheme means a query for "yesterday" reads one day of files, not the whole table. You pay less for the bytes scanned (compute) and the engine touches less of the object store (I/O). Over-partition, though - say by user_id - and you recreate the small-file problem with one tiny file per partition. The art is picking a column selective enough to prune but coarse enough to keep files fat.
Compute: stop paying for idlethe biggest dumb-money leak
- Right-size clusters. Match worker type and count to the job's shuffle and memory profile, not a copy-pasted default that's 4x too big.
- Autoscale and auto-terminate. Scale workers to the workload and kill idle clusters - an interactive cluster left running overnight is pure waste.
- Spot for the interruptible. Backfills and stateless batch ride spot/preemptible instances; keep on-demand for the latency-critical tier-1 path.
- Tune the job. Fix skew, prefer broadcast joins for small dimensions, cache reused datasets and turn on Photon where the workload suits it.
Attribution: make teams see their own spendyou can't optimize what no one owns
A single platform bill nobody can decompose is a bill nobody will reduce. Tag every cluster and job by team and pipeline, lean on Unity Catalog system tables for usage and surface a per-team breakdown. Showback (here's your spend) usually comes before chargeback (it hits your budget) - you earn the right to charge back by running clean, trusted showback first.
Tiering and the replay windowthe question that decides retention
- Hot
- Recent, frequently queried - fast storage, full fidelity, fully indexed
- Cold / archive
- Old, rarely read - cheap tier, accept slower retrieval
- Replay window
- How far back you might need to reprocess raw from scratch
- Past the window
- Drop or pre-aggregate raw - keep the rollup, shed the row-level cost
The replay window is the honest answer to "why are we still paying to store 18-month-old raw events?"
Cost is the differentiator most data candidates forget. Whatever the design question - ingestion, modeling, observability - close with a cost angle unprompted: "and here's what this costs and the one lever I'd pull first." For unit economics, frame it as cost per million events or per query, not the raw monthly bill - the ratio tells you whether spend grew from more usage (fine) or more waste (a problem). That instinct is exactly the pragmatic, cost-conscious judgment the JD calls out.
Takeaway. Split the bill into storage (compaction, partition pruning, retention) and compute (right-size, autoscale, spot, kill idle), attribute spend per team so it gets owned and reason in unit economics (cost per million events) rather than the raw total.
Self-check
QReads on a streaming-ingested bronze table have gotten painfully slow and the storage bill is climbing, even though total data volume looks reasonable. What's the most likely root cause and the first fix?
Governance, security & privacy
After this you can protect sensitive product and agent data.
Cursor's data is unusually sensitive: it can include developers' code and how they use an AI coding tool and some of it feeds model and agent work. The JD asks you to expand agent-data capabilities while upholding security and privacy. That tension is the whole section.
Governance is not a compliance afterthought you bolt on at the end. At this scale it's an architecture decision you make on day one, because retrofitting access controls onto a sprawling lakehouse is a nightmare you want to avoid.
Unity Catalog as the control planeone place for access, lineage, audit
- RBAC / ABAC
- Grants by role and by attribute, one model across every workspace and table
- Lineage
- Column-level lineage so you can trace where PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive. flows downstream
- Audit
- Who read what, when - the log you need for an incident or a regulator
- Discovery
- A catalog so users find data without DMing you for table names
Centralizing governance means a policy change happens once, not table-by-table across the lake.
Producers, consumers and the data contractwho owns correctness when data crosses teams
Ownership gets murky once data crosses team lines - analytics, accounting and engineering all touch the same numbers. A clean mental model is producers vs. consumers. When finance runs its close on platform data, finance is the consumer; the partner teams emitting the upstream tables are the producers. The thing that makes the relationship work is an explicit data contract negotiated with those producers, covering three dimensions.
- Completeness
- Every row that should be there is there - no silently dropped partitions feeding the close
- Accuracy
- The values are correct, not just present - the producer asserts on content, not only on the job running
- Timeliness
- The data lands inside the window the consumer needs it (a close has a hard calendar deadline)
Snapshot-and-diff backs the contract: take snapshots as data changes and run reconciliations against them, so a breach is caught against a known-good baseline rather than discovered at close.
A finance-engineering team framed governance for the close exactly this way - producers, consumers and a contract - while being honest that the snapshot-and-diff reconciliation around it is still maturing.
"Having really clear understanding of the kind of... the contract, the data contract around completeness and accuracy, and timeliness."
PII: classify, then controlyou can't protect what you haven't found
- 1Classify first. Tag columns by sensitivity (PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive., code content, internal-only). You can't apply a policy to data you haven't labeled.
- 2Mask or tokenize at rest. Replace raw PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive. with masked or tokenized values so most consumers never touch the original.
- 3Column- and row-level security. Grant the marketing analyst the aggregate, not the email; scope rows by tenant where it applies.
- 4Least privilege by default. Access is requested and granted, not the ambient default - and it's reviewed, not granted forever.
"We need this data to make the agent better" is true and is also exactly where privacy discipline slips. Code and usage data is some of the most sensitive a developer owns. Expanding capability means building the guardrails alongside it: opt-in/consent handling, masking of secrets and PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive. before training use, isolated environments and an audit trail - not shipping the capability now and promising controls later. Saying this unprompted in the interview signals you understand the stakes of the role's flagship project.
Separate environments to bound blast radiustraining vs. analytics vs. raw
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
Separation by design: a leak in analytics cannot reach raw unmasked PII and the agent feed lives apart from both.
- Environment
- Raw / bronze
- Who/what reads it
- Pipelines only, near-zero human access
- Control posture
- Tightest access; may hold unmasked PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive., so it's the most locked-down tier
- Environment
- Analytics (silver/gold)
- Who/what reads it
- Analysts, BI, internal stakeholders
- Control posture
- PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive. masked or excluded; row/column security; broad-ish but governed
- Environment
- Training / agent data
- Who/what reads it
- Model and agent pipelines
- Control posture
- Isolated, consent-gated, secrets and PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive. scrubbed; separate credentials
| Environment | Who/what reads it | Control posture |
|---|---|---|
| Raw / bronze | Pipelines only, near-zero human access | Tightest access; may hold unmasked PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive., so it's the most locked-down tier |
| Analytics (silver/gold) | Analysts, BI, internal stakeholders | PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive. masked or excluded; row/column security; broad-ish but governed |
| Training / agent data | Model and agent pipelines | Isolated, consent-gated, secrets and PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive. scrubbed; separate credentials |
Separation means a leak or a bad query in analytics can't reach raw unmasked data - the blast radius is contained by design.
Retention, deletion and the right to be forgottendeletion across a lakehouse is genuinely hard
A deletion request is easy to honor in a single transactional database and hard across a lakehouse where one user's events are scattered through partitioned Parquet, copied into silver, aggregated into gold and maybe cached. You need a plan: a way to find every copy via lineage, Delta's delete/vacuum to physically remove rows and retention policies that age data out so you're not hoarding what you don't need.
"We deleted the row" is incomplete if the data was also pre-aggregated into gold, copied to a training set or sitting in a cached extract. Use lineage to enumerate every copy, delete and vacuum the underlying files (a logical delete that leaves old Delta versions isn't gone) and confirm the replicas. Deletion that only hits the obvious table is the kind of gap an audit finds for you.
Takeaway. Centralize access, lineage and audit in Unity Catalog; classify then mask/restrict PIIPersonally Identifiable Information. Data that can identify a person (names, emails, SSNs); regulated and sensitive. at least privilege; isolate raw vs. analytics vs. training data to bound blast radiusHow much breaks if a change goes wrong; the scope of potential damage.; and treat deletion as a lineage-driven sweep across every copy, not a single DELETE.
Self-check
Tooling & build-vs-buy decisions
After this you can make defensible decisions on the data tool stack.
The JD hands you real authority: evaluate and deploy BI platforms, catalogs, ingestion connectors and reverse-ETL. So expect a build-vs-buy question and expect the interviewer to care about your reasoning far more than which vendor you name.
As one of the first data platform engineers, your time is the scarcest resource on the team. Build-vs-buy is really a question about where your hand-rolled engineering creates durable advantage and where it's just reinventing a solved commodity.
The decision frameworkfive lenses, not vendor hype
- Lens
- Total cost
- The question you ask
- License + the engineering time to integrate and run it, not just the sticker
- Lens
- Scale fit
- The question you ask
- Does it survive billions of events/day or quietly cap out at your current volume?
- Lens
- Lock-in
- The question you ask
- How painful is leaving? Proprietary formats and one-way doors raise the bar to buy
- Lens
- Team capacity
- The question you ask
- Does buying free your tiny team to build the differentiated parts?
- Lens
- Time-to-value
- The question you ask
- Working next week vs. a quarter of platform work before anyone benefits
| Lens | The question you ask |
|---|---|
| Total cost | License + the engineering time to integrate and run it, not just the sticker |
| Scale fit | Does it survive billions of events/day or quietly cap out at your current volume? |
| Lock-in | How painful is leaving? Proprietary formats and one-way doors raise the bar to buy |
| Team capacity | Does buying free your tiny team to build the differentiated parts? |
| Time-to-value | Working next week vs. a quarter of platform work before anyone benefits |
Run any tool decision through these. The answer is rarely the same for every layer of the stack.
The usual answer per layerwhere the industry tends to land
Interactive diagram. Tab through its regions; each focused region shows its detail in the panel below.
Build only where scale makes it the moat; buy the commodity so your tiny team's build budget compounds.
Buy (Fivetran/Airbyte) for third-party SaaS sources - Salesforce, Stripe, ad platforms. Connectors are a commodity and not worth hand-building.
Build for first-party product telemetry at billions/day - that scale and the exact-once/schema needs are your differentiator and the JD's core ask.
Looker, Tableau or Hex consume the gold layer for dashboards and self-serve.
Building a BI tool from scratch is almost never the right move - buy and put your effort into a clean, trustworthy gold layer beneath it.
Unity Catalog comes with the Databricks lakehouse; lean on it for governance, lineage and discovery.
Reach for a third-party catalog only if a real gap appears, not preemptively.
Push modeled gold data back into CRM, product and billing tools (e.g. Hightouch/Census).
Syncing to dozens of operational SaaS APIs reliably is a solved commodity - buying it frees you for platform work.
The thread through all of it: buy the commodity, build the differentiator. Your moat is the first-party ingestion at extreme scale and a reliable, governed lakehouse - not a homegrown dashboard tool.
Reverse-ETL, brieflythe gold layer flows back out
Most pipelines pull data in to model it. Reverse-ETL pushes the modeled result back out - a churn score computed in gold lands in the CRM so a rep sees it or a usage tier syncs to billing. It closes the loop so the data platform drives operational tools, not just dashboards.
When you get the build-vs-buy question, never answer with a single tool name. Walk the framework, then split by layer: "Buy connectors for third-party SaaS, but build first-party ingestion at our scale because that's the differentiator and a commodity tool would cap out." Naming the exception - the one place you'd build against the default - is what shows judgment rather than a memorized preference.
The trap for a strong engineer is building things that should be bought because building is more fun. At a tiny early team, every week spent reinventing a Fivetran connector is a week not spent on the lakehouse only you can build. Bias to buy the commodity; spend your scarce build budget where it compounds.
Takeaway. Run tool decisions through total cost, scale fit, lock-in, team capacity and time-to-value - then buy the commodity (SaaS connectors, BI, reverse-ETL) and build the differentiator (first-party ingestion at billions/day, the governed lakehouse), naming the one exception that proves you reasoned rather than memorized.
Self-check
QYou're asked: "Would you build or buy your ingestion?" Give an answer that shows judgment rather than a blanket preference.