cswork / libraryOpen practice workspace

Articles · Harvey

Harvey Software Engineer Interview Guide 2026: Coding, Legal AI Systems, and Product Judgment

Prepare for Harvey software interviews with a runnable vault, authorization and citation traces, source-version checks and a timed legal-AI design rehearsal.

A Harvey-focused software rehearsal should make document access and citation support observable. “Use retrieval and generate an answer” is too vague when a source is revoked, a version changes or the evidence does not support the requested claim. This guide completes a small vault slice and traces those failures before expanding the design.

Use the Harvey Software Engineer practice collection to select additional drills. The vault here is an original teaching model, not Harvey’s code or a leaked interview exercise.

Design around provenance and access

For an original architecture rehearsal, accept a question over documents in one permitted matter and return claims with exact citations. State five invariants: no unauthorized content reaches the response path; citations identify the permitted source version; changed access has a defined invalidation policy; insufficient evidence cannot become a confident unsupported answer; and replayed work has an explicit idempotency boundary.

During ingestion, preserve an immutable version ID and locations that connect extracted text back to the source. Store tenant, matter and version identity with chunks and indexes. A retry should not silently create two active versions. Separate ingestion failures from search over already-available sources so one failed batch does not block unrelated work.

At retrieval, carry trusted authorization context into the data query. Combining lexical and semantic candidates can help some questions, but it does not replace access enforcement. Before generation, assess whether the selected evidence covers the requested claim. Missing dates, jurisdictions or conflicting passages can require clarification or abstention.

At delivery, validate citation spans, source versions and current access. A quotation appearing in a document does not prove the generated interpretation follows from it. Bind each material claim to supporting evidence and retain a review path for uncertainty. The runnable slice deliberately checks only a much smaller contract.

A runnable first slice of a document vault

Use this fictional fixture to make the trust boundary visible. A document belongs to one tenant and one matter. Its current version contains immutable text. A user has explicit grants to tenant/matter pairs. A response must use the requested current version and a quotation that actually appears in that text. This is a sequential teaching model, not Harvey’s implementation or a proof of production security.

from dataclasses import dataclass

@dataclass(frozen=True)
class Document:
    tenant: str
    matter: str
    doc_id: str
    version: int
    text: str

class Vault:
    def __init__(self, documents, grants):
        self.documents = {(d.tenant, d.matter, d.doc_id): d for d in documents}
        self.grants = set(grants)

    def cite(self, user, tenant, matter, doc_id, version, quotation):
        if (user, tenant, matter) not in self.grants:
            return {"status": "denied"}
        document = self.documents.get((tenant, matter, doc_id))
        if document is None:
            return {"status": "not_found"}
        if document.version != version:
            return {"status": "stale_source"}
        if not quotation or quotation not in document.text:
            return {"status": "insufficient_evidence"}
        return {
            "status": "supported",
            "citation": {"doc_id": doc_id, "version": version, "quotation": quotation},
        }

    def revoke(self, user, tenant, matter):
        self.grants.discard((user, tenant, matter))

vault = Vault([
    Document("t1", "m1", "d1", 2, "The agreement renews on 1 July."),
    Document("t2", "m9", "d1", 1, "A different tenant document."),
], {("alice", "t1", "m1")})
allowed = vault.cite("alice", "t1", "m1", "d1", 2, "renews on 1 July")
assert allowed["status"] == "supported"
assert allowed["citation"]["version"] == 2
assert vault.cite("alice", "t2", "m9", "d1", 1, "different")["status"] == "denied"
assert vault.cite("alice", "t1", "m1", "d1", 1, "renews")["status"] == "stale_source"
assert vault.cite("alice", "t1", "m1", "d1", 2, "renews on 1 August")["status"] == "insufficient_evidence"
vault.revoke("alice", "t1", "m1")
assert vault.cite("alice", "t1", "m1", "d1", 2, "renews")["status"] == "denied"

The document ID alone is not a lookup key; d1 exists in two tenants. Authorization precedes document lookup, so the denied response does not reveal whether the other tenant’s document exists. Revocation is checked again on each call. That handles sequential calls in this fixture; concurrent revocation, cached permissions and long-running generation need a real policy and synchronization strategy.

Trace three requests all the way to an output

Allowed: Alice requests tenant t1, matter m1, document d1, version 2 with the quotation “renews on 1 July.” The grant exists, the compound key resolves, the version matches and the substring is present. Return supported with document ID, version and exact quotation.

Denied: Alice requests t2/m9/d1. There is no matching grant. Return only denied; do not retrieve text, query an embedding cache without tenant scope, or produce a response that identifies another tenant’s matter.

Revoked: After removing Alice’s grant for t1/m1, repeating her previously allowed request returns denied. A cached answer must not bypass the current permission check. In a production system, define when revocation becomes effective and how in-flight responses are reauthorized before delivery.

The stale-version and unsupported-quotation checks are additional failure paths. A real citation needs offsets or another stable span reference, document provenance and context. Substring presence cannot prove that a generated conclusion follows from the passage. For example, “the agreement renews” does not establish the notice period. Return insufficient evidence or ask for the relevant source rather than filling the gap with a plausible legal statement.

Extend the slice without hiding its limits

Keep retrieval scoped by tenant and matter. Associate chunks, embeddings and results with a document version; reindexing must not mix old and current content silently. Include authorization context in cache keys and recheck access before delivery. Record an audit event containing identifiers and the decision without unnecessarily logging confidential source text. Harvey’s published engineering discussion makes secure embedding storage a relevant topic to study; this fixture remains an independent exercise. Harvey embedding security.

The in-memory constructor assumes one current document per compound key and validated inputs. A production write path needs duplicate handling, immutable versions, authenticated identity, storage isolation and an explicit permission model. It also needs tests against real retrieval and caching layers. Passing this fixture cannot establish those properties.

A 40-minute Harvey-focused rehearsal

Use five related prompts: implement the vault lookup, add citation validation, explain a version update, trace permission revocation, and design a retrieval service with a slow or failed model call. These are original practice prompts, not Harvey’s disclosed questions.

Spend five minutes on the contract, fifteen on the initial slice, ten on tests and ten on follow-ups. Finish only when you can demonstrate an allowed citation, a cross-tenant denial, a post-revocation denial, a stale version and an unsupported quotation. Then explain what remains unproven about concurrency and meaning. A strong discussion names those limits while keeping the first implementation small.

Harvey’s current candidate overview discusses the company and its work but does not establish one fixed software interview sequence. Confirm your team, level, assessment format and AI-use instructions with your contact. Harvey candidate overview.

Trace a source update and a cached response

Suppose document t1/m1/d1 changes from version 2 to version 3. A cached response quoting version 2 must not silently present itself as an answer over the current source. Decide whether historical versions remain available, whether the question requested a particular version and how the UI identifies that choice. A cache key needs enough source and authorization context to preserve the contract.

If permission is revoked, an old cache hit must not bypass the current access check. Define the effective revocation window and what happens to an answer already in progress. A conservative response path rechecks permission before delivery and uses a generation or other invalidation identity to reject stale authorization state. The exact mechanism requires the real service and consistency model; the sequential Python fixture does not implement it.

For deletion, include derived state: extraction text, chunks, embeddings, cached answers and temporary artifacts. Document the retention and invalidation policy rather than claiming that deleting the original object instantly erases every copy. Keep recovery and audit requirements compatible with that policy.

Add request and response identity

An original request could include matter_id, question, selected document_versions and a client request ID, while trusted tenant and user identity come from authentication. A supported response should include claim text, document ID, version, source span and the quoted evidence. An insufficient-evidence response should identify the missing kind of support without exposing unauthorized document existence.

For the fictional source, “The agreement renews on 1 July” can support a quotation of that clause. It does not supply a thirty-day notice requirement. If the question asks for the notice period, the system should request the relevant evidence or state that it is not established. A citation can be valid as text while the claim is unsupported as meaning.

Review five failure classes independently

Use separate checks for cross-tenant retrieval, stale source identity, changed access, unsupported claims and operational failure. A model timeout should produce a recoverable job state or clear error; it should not return a fabricated answer. A partial ingestion failure should not create a “current” source that lacks required pages without marking completeness.

For evaluation, preserve exact fixtures and expected outputs. Check both denial and allowed behavior so a system that rejects every request does not appear correct merely because it has no access violations. Assess whether abstention happens when evidence is missing and whether supported questions still receive useful, reviewable answers.

The final design discussion should say what the runnable slice proves and what remains for integration testing: authenticated identity, storage isolation, index scoping, cache behavior and concurrent revocation. That boundary makes the answer more credible than claiming production security from a small set of local assertions.

Review the full design after the first slice

Add tests for poor extraction, conflicting documents, deletion, stale indexes, cache invalidation and a model timeout. Report permission violations, citation errors, unsupported claims, abstention quality and latency separately. An aggregate quality score can conceal a critical access failure.

For a real-project discussion, prepare a short user/outcome account, an architecture explanation and one component-level failure trace. Name what you owned, the simpler alternative, a changed assumption, the scope you cut and the outcome you can defend. Use confidential examples only at an appropriate abstract level; source text and client identities are unnecessary.

Does substring validation prove legal correctness?

No. It establishes a limited text-presence condition in a fictional fixture. Meaning, context, source authority and professional review are additional concerns. Do not convert the example’s supported status into a claim that an arbitrary legal conclusion is valid.

What if access changes during generation?

Define the revocation policy and reauthorize before delivery. A sequential set lookup does not settle concurrent requests, cached grants or an answer already being streamed.

Are the stages in every Harvey loop identical?

No fixed sequence is established here. Confirm your team, level, assessment and AI instructions using the current role and recruiting contact.

Sources and Further Reading

Editorial revision: 8 October 2026. Current hiring details remain role-specific; unavailable source pages and unverified timings are identified in the text.