← h2 Interview Insights

h2·Software Engineer·Onsite - System Design / Architecture·Senior

SeniorPrefer not to say
Apr 2026

Summary

System design round at h2 for a software engineer role. The whole thing was basically one massive open-ended question about building an annotation workflow engine from scratch, and they let you use Claude which was a nice surprise but also kind of made me second-guess how much I was actually being evaluated on.

Questions Asked (5)

Q1

Design an annotation workflow engine that supports dual-review pipelines, conflict adjudication, revision loops, and a full analytics layer. Walk through the data model, state machine, APIs, assignment strategies, and how you'd handle scale and extensibility.

System DesignData ModelingAPI & Integrations
Author's notes

This is a beast of a question.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and scale, then present a layered architecture: data model, state machine, APIs, assignment, and analytics. Walk through the dual-review pipeline and conflict adjudication with concrete examples, and discuss how each layer scales and extends.

Pro tip: Emphasize idempotency and auditability in the state machine and APIs, as these are critical for reliable annotation workflows and analytics. Also, mention that you'd use event sourcing or an append-only log to capture all state changes for analytics and debugging.

1. Clarify Requirements and Scope

Ask about scale (tasks per day, concurrent annotators), review types (dual-review, adjudication), revision policies, and analytics needs. Confirm non-functional requirements like latency, consistency, and extensibility.

2. Design the Data Model

Define core entities: Task, Annotation, Review, User, Assignment, and AuditLog. Use an append-only event log for state changes to support analytics and traceability.

3. Define the State Machine

Model task states (e.g., CREATED, ASSIGNED, ANNOTATING, REVIEWING, ADJUDICATING, REVISION, COMPLETED) and transitions. Ensure idempotent transitions and handle revision loops by allowing tasks to re-enter earlier states.

4. Design APIs and Assignment Strategies

Expose RESTful or gRPC APIs for task management, annotation submission, review, and adjudication. Implement assignment strategies (e.g., round-robin, skill-based, load-balanced) and support dynamic re-assignment.

5. Address Scale, Extensibility, and Analytics

Use sharding, caching, and async processing for scale. Design for extensibility via pluggable review policies and annotation types. Build an analytics layer using materialized views or stream processing on the event log.

Key Points to Mention

  • Event sourcing or append-only log for auditability and analytics
  • Idempotent state transitions and API operations to handle retries
  • Conflict adjudication workflow: when dual reviews disagree, route to adjudicator with context
  • Revision loops: allow tasks to be sent back for re-annotation with feedback
  • Assignment strategies: consider annotator expertise, workload, and fairness
  • Scalability: partition by task ID, use queues for async processing, and cache hot data

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

How would you handle idempotency in the annotation submission API, especially with retries and concurrent annotators?

API & IntegrationsTechnical Trade-offsSystem Design
Author's notes

They pulled this out as a specific follow-up after I described the submit-annotation endpoint.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements: what does idempotency mean for annotation submissions (e.g., preventing duplicate annotations from retries) and how concurrent annotators affect it. Then propose a design using idempotency keys and database constraints to ensure exactly-once semantics, and discuss trade-offs like performance and complexity.

Pro tip: Mention that idempotency keys should be generated client-side and stored with a unique constraint, and that you'd return the same response for duplicate requests to simplify client retry logic.

1. Clarify requirements and scope

Ask questions to understand what idempotency means here: should duplicate submissions be ignored, merged, or rejected? How are retries triggered (client, network)? What is the expected concurrency level?

2. Design idempotency mechanism

Propose using a client-generated idempotency key (e.g., UUID) sent with each submission. Store it in a database table with a unique constraint, along with the response, to detect and handle duplicates.

3. Handle concurrent requests

Use database transactions with appropriate isolation levels (e.g., serializable or unique constraint checks) to prevent race conditions. Consider optimistic concurrency control or distributed locks if needed.

4. Define retry semantics

Ensure that retries with the same idempotency key return the original response (or a 409 Conflict if still processing). Implement exponential backoff and jitter on the client side.

5. Discuss trade-offs and alternatives

Compare database constraints vs. distributed locks vs. event sourcing. Address performance impact, storage overhead, and cleanup of old idempotency keys.

Key Points to Mention

  • Idempotency key generation and transmission (e.g., in header or body)
  • Database unique constraint on idempotency key to enforce exactly-once
  • Transaction isolation levels and handling of concurrent inserts
  • Returning consistent responses for duplicate requests (e.g., same status code and body)
  • TTL or cleanup strategy for idempotency keys to avoid unbounded storage
  • Client-side retry logic with exponential backoff and idempotency key reuse

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

How would you design the system to support new pipeline shapes beyond dual-review, say a three-way review or a single-pass pipeline?

System DesignTechnical Trade-offsAdaptability & Ambiguity
Author's notes

Extensibility question.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the current dual-review pipeline and the requirements for new shapes, then propose a flexible abstraction that decouples pipeline stages from their orchestration. Discuss how to model stages as composable units and use a configuration-driven approach to define different pipeline shapes, while addressing trade-offs in complexity, performance, and maintainability.

Pro tip: Emphasize that the goal is not to build a general workflow engine but to find the simplest abstraction that supports the known shapes and can evolve. Show awareness of over-engineering and suggest starting with a minimal viable abstraction, then iterating based on real needs.

1. Clarify requirements and constraints

Ask questions to understand the current dual-review pipeline, the specific new shapes (three-way review, single-pass), and non-functional requirements like latency, throughput, and consistency. Identify what varies and what stays the same across shapes.

2. Identify common abstractions

Extract the core building blocks: stages (e.g., review, approval), transitions, and data flow. Propose modeling each stage as an independent, reusable component with well-defined inputs/outputs, and separate the pipeline definition from execution.

3. Design a flexible orchestration layer

Introduce a pipeline definition (e.g., via configuration or DSL) that specifies the sequence and conditions of stages. Use a lightweight orchestrator that interprets the definition and manages state, retries, and error handling.

4. Address trade-offs and extensibility

Discuss trade-offs: added complexity vs. flexibility, potential performance overhead, and impact on existing dual-review. Suggest how to migrate incrementally and how to ensure backward compatibility.

5. Validate with examples and edge cases

Walk through how the design supports three-way review and single-pass, including failure scenarios and dynamic changes. Mention testing strategies and monitoring to ensure correctness.

Key Points to Mention

  • Separation of concerns: pipeline definition vs. execution engine
  • Configuration-driven or DSL-based pipeline specification
  • Composability and reusability of stages
  • State management and idempotency across stages
  • Trade-offs: flexibility vs. complexity, performance overhead
  • Incremental migration and backward compatibility with dual-review

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Walk through the pluggable assignment strategies. How would round-robin, skill-based, and load-balancing differ in implementation, and how do you swap between them?

System DesignTechnical Trade-offsData Modeling
Author's notes

Strategy pattern, basically.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining a common interface for assignment strategies, then explain how each strategy implements it differently. Describe how a factory or dependency injection allows swapping strategies at runtime or configuration time, and discuss trade-offs like fairness, efficiency, and complexity.

Pro tip: Emphasize that the strategy pattern decouples the assignment logic from the core system, making it easy to add new strategies without modifying existing code. Mention that you'd use feature flags or configuration to swap strategies in production without redeploying.

1. Define the Strategy Interface

Create a common interface (e.g., AssignmentStrategy) with a method like assign(task, agents) that returns the selected agent. This ensures all strategies are interchangeable.

2. Implement Round-Robin

Maintain a circular counter or queue of agents. Each assignment picks the next agent in sequence, wrapping around. Simple but ignores agent skills and current load.

3. Implement Skill-Based

Filter agents by required skills for the task, then select among qualified agents (e.g., by least recent assignment or random). Requires a skill matrix or tagging system.

4. Implement Load-Balancing

Track current load (e.g., number of active tasks) per agent and assign to the least loaded. May need real-time metrics and can be combined with skill filtering.

5. Enable Swapping

Use a factory or dependency injection to instantiate the desired strategy based on configuration. Allow runtime swapping via a strategy manager that holds the current strategy and can replace it.

Key Points to Mention

  • Strategy pattern and interface-based design for pluggability
  • Round-robin: simplicity, fairness, but ignores skills/load
  • Skill-based: requires skill data, ensures competence, but may cause imbalance
  • Load-balancing: optimizes utilization, needs load metrics, may neglect skills
  • Swapping mechanism: factory, dependency injection, configuration, or feature flags
  • Trade-offs: complexity, performance, fairness, and maintainability

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

What metrics would you expose in the analytics layer, and how would you compute per-annotator agreement rates at scale?

Product Analytics & MetricsSystem DesignTechnical Trade-offs
Author's notes

I listed throughput, queue depth, time-to-completion, adjudication rate, and Cohen's kappa per annotator.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the product context and what decisions the analytics layer should support, then propose a tiered metric set covering volume, quality, and throughput. For per-annotator agreement at scale, describe a streaming or batch pipeline that computes pairwise agreement incrementally, using sketches or sampling to bound cost while preserving statistical validity.

Pro tip: Emphasize that agreement metrics must be paired with calibration and adjudication workflows; raw agreement alone can incentivize gaming. Also mention that you'd version metric definitions and store raw annotation events so you can recompute agreement when the label schema evolves.

1. Clarify goals and constraints

Ask what decisions the metrics will drive (e.g., quality control, annotator feedback, pricing) and what scale/latency requirements exist. This shapes whether you need real-time streaming or daily batch computation.

2. Define the metric taxonomy

Propose metrics across three layers: volume (tasks completed, annotations per hour), quality (agreement, accuracy against gold, calibration), and operational (throughput, latency, cost per annotation). Tie each metric to a specific action.

3. Design the agreement computation pipeline

Describe how to compute per-annotator agreement efficiently: use incremental statistics (e.g., Cohen's kappa, Krippendorff's alpha) over pairwise comparisons, pre-aggregate by item and annotator, and leverage sampling or approximate sketches for high-volume streams.

4. Address scale and trade-offs

Explain how to handle millions of annotations: partition by project/time, use map-reduce or streaming windows, cache intermediate results, and choose between exact vs. approximate methods based on cost and required precision.

5. Close with monitoring and iteration

Mention how you'd monitor metric drift, detect annotator degradation, and feed insights back into training and task design. Highlight the importance of versioning and reproducibility.

Key Points to Mention

  • Cohen's kappa and Krippendorff's alpha as standard agreement measures, with pros/cons for different data types
  • Incremental/streaming computation using pairwise confusion matrices and sufficient statistics
  • Sampling or sketching (e.g., HyperLogLog, count-min sketch) to bound memory and compute at scale
  • Separation of raw annotation events from derived metrics for recomputability and auditability
  • Trade-offs between exact and approximate agreement, and between real-time and batch processing
  • Integration with quality control workflows: gold questions, adjudication, and annotator feedback loops

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.