Owns identity, policy, workflow state, budgets, approvals, leases, and audit. It decides what may happen.
System design field manual · Mock 01
Design an auditable AI software factory.
A realistic interview transcript and visual reference for a multi-tenant control plane that connects intent to code, runs durable agents, and can explain every consequential action.
- Candidate
- You · Staff-level full-stack / distributed systems
- Format
- Live architecture review
- Clock
- 30 minutes · 9 timed acts
- Deep dives
- Versioned provenance + durable multi-model execution
- Difficulty
- Enterprise critical
Definitions and mental model
Forge is not “ChatGPT that writes code.” It is an authority system wrapped around fallible workers.
Runs untrusted or failure-prone work: repository parsing, model calls, tools, tests, and sandboxed agents.
A typed, version-specific claim that one thing derives from, implements, tests, contradicts, or supersedes another.
Logical work survives process, machine, provider, and region failures because progress is checkpointed outside the worker.
The central invariant
Models propose; policy and humans authorize. An agent may create a suggestion or pull request. It never silently rewrites published truth.
The storage split
Immutable versions and audit events preserve history. Transactional current views make the product usable. Derived indexes are rebuildable.
The delivery promise
A release pins exact versions of requirement, blueprint, commit, tests, policy, model inputs, approvals, and receipts.
Drive from consequences to invariants to data. Technology names come after you can state what must never happen.
Opening and scope
Listen, restate, and spend your first questions buying down ambiguity.
Interviewer · starting question Design Forge: a multi-tenant system where product teams create requirements and blueprints, turn them into dependency-aware work orders, run coding agents for minutes or hours, connect changes to repositories and tests, detect drift, and export a complete audit trail. Start with scope and invariants, estimate load, then show data, APIs, architecture, provenance, and durable execution.
Assume 250 enterprises, 200,000 users, 20,000 projects, 80,000 repositories, 500 million provenance edges, 15,000 webhooks per second at peak, and 5,000 concurrent agent runs. Where do you start?
I will first define what Forge is authoritative for. I hear three systems with different failure semantics: a collaborative system of record, a rebuildable code/search intelligence plane, and a long-running workflow engine that touches unreliable external systems.
Before drawing boxes: are published artifacts immutable? Is drift advisory or release-blocking? What may an agent do without human approval? Must audit replay reproduce an identical model output, or prove the exact observable inputs, policy, calls, outputs, and approvals?
Published versions are immutable. Drift is advisory until a customer makes it a release policy. Agents may read, analyze, run tests, and open a PR; merging and deployment require human approval. Audit must explain and verify an action, not regenerate identical tokens.
Good. I will optimize the control plane for correctness and availability, while keeping expensive fan-out asynchronous. My north-star invariant is: every material output names the immutable input-version manifest and the principal, policy, model/tool configuration, and approvals that produced it.
I will keep model training and language-parser implementation out of scope, but define provider and indexing interfaces. I will also treat repository text as untrusted data; retrieved code cannot grant itself more tool permissions.
Requirements become invariants
Translate product verbs into rules the architecture must protect.
What are your functional and nonfunctional priorities?
My critical write path is author, review, and publish immutable artifact versions; create and transition work orders; reserve budget; acquire a run lease; and record approval or external side-effect receipts. These require transactional checks.
Search, semantic embeddings, symbol indexing, drift, analytics, notifications, and large impact closure are derived. They may converge, but must expose generation and freshness. The user should never confuse “index caught up” with “truth committed.”
Can a product manager publish while a 100,000-edge impact computation is running?
Yes. The publication transaction writes the immutable version, appends an outbox event, and returns. An impact worker consumes the event, traverses a bounded snapshot, stores findings by analysis generation, and emits progress. A release gate can require generation G to complete before release, without holding publication hostage.
Authority
A published version never changes. Corrections create a successor. A release pins exact versions, never “latest.”
Isolation
Every access path—including search, cache, log, prompt, and eval—is tenant- and policy-scoped.
Execution
One logical run can have many attempts; only the current fenced lease may advance state.
Evidence
Auditable means observable evidence and version manifests, not hidden chain-of-thought or guaranteed identical generation.
| Need | Target | Design consequence | Degrade safely as |
|---|---|---|---|
| Authoritative writes | P95 < 300 ms; 99.95% | Regional transactional authority, optimistic concurrency, outbox | Read-only with explicit status if quorum is unavailable |
| Collaboration | Remote update < 250 ms | Ephemeral presence + operation stream; publish remains separate | Local draft and reconnect conflict UI |
| Drift | First finding < 5 min | Priority queue, incremental index, partial generation markers | Stale badge; block only if policy says so |
| Agent runs | 1 min–8 hr; 5,000 active | Leases, heartbeats, checkpoints, cancellation epoch, quotas | Continue without live stream; pause before privileged step |
| Disaster recovery | RPO < 1 min; RTO < 30 min | Cross-region log replication, fenced failover, rehearsed restore | No dual writers; preserve safety over write availability |
| Audit | 7 years | Append-oriented events, WORM export, integrity manifests, legal hold | Audit querying can lag; recording cannot silently drop |
Back-of-the-envelope first
Use estimates to find the expensive paths: not user CRUD, but write amplification, fan-out, indexing, and long-lived work.
Give me enough math to defend your partitions and asynchronous boundaries.
At 1,000 normal and 5,000 peak authoritative mutations per second, the primary store is not extraordinary, but each logical action can emit audit, outbox, notification, graph, and index work. At a conservative 8 derived events per mutation, peak internal ingress is about 40,000 events per second.
Fifteen thousand webhook deliveries per second at roughly 2 KB each is 30 MB/s before repository fetches. I acknowledge after signature verification and durable dedupe, then coalesce by repository/ref and reconcile to the provider's current commit rather than processing arrival order.
Five thousand active runs with a 30-second heartbeat is about 167 heartbeats/second. If each produces a 256 KB checkpoint every five minutes, checkpoint ingress is only about 4.3 MB/s—but retaining every checkpoint indefinitely would be wasteful, so I compact successful runs and preserve policy-relevant receipts.
Write amplification
5,000 writes/s × 8 events ≈ 40,000 events/sPartition by tenant/project and event family; avoid one global ordering requirement.
Webhook burst
15,000/s × 2 KB ≈ 30 MB/sDurable ingress is cheap; fetching and parsing monorepos is not. Coalesce before work.
Run heartbeat
5,000 ÷ 30 sec ≈ 167/sThe scheduler bottleneck is fairness and side effects, not raw heartbeat throughput.
Audit & provenance capacity calculator
Move the assumptions. The formulas update locally—no data leaves this page.
Planning model only, using binary capacity units: compression, hot/cold tiers, index shape, legal holds, and tenant skew change real capacity. The point is to expose assumptions.
Workload shape matters more than averages
Bars compare architectural pressure, not common units. Fan-out and tenant skew drive queues, cache policy, and work limits.
Data model and contracts
Stable logical identity, immutable versions, typed relationships, and idempotent commands form the spine.
Show me the minimum schema. Be precise about identity and versioning.
Artifact is a stable logical object. ArtifactVersion is immutable content and structured metadata addressed by version ID and content hash. A Publication pins a reviewed set of version IDs. “Latest” is a UI projection, never a release dependency.
A ProvenanceEdge connects specific version/span endpoints and records type, asserter, evidence, confidence, and validity. Work-order dependencies are separate because they have workflow invariants such as acyclicity and readiness.
For agents, AgentRun is the logical intent; RunAttempt represents a worker try. Checkpoints, model calls, tool calls, side-effect receipts, budget reservations, approvals, and audit events all key back to tenant, project, run, and attempt.
Core entity model
Stable ID ≠ immutable version| Record | Primary identity | Critical invariant | Main access pattern |
|---|---|---|---|
ArtifactVersion | (org_id, project_id, version_id) | Content/hash immutable after commit | Resolve a release or compare parent/successor |
ProvenanceEdge | (tenant_partition, edge_id) | Both endpoints are exact versions/spans | Bounded inbound/outbound traversal by type |
WorkOrderDependency | (project_id, from_id, to_id) | No cycle; readiness computed from terminal prerequisites | Ready queue, dependency update |
AgentRun | (org_id, run_id) | One logical billable intent; monotonic state version | Status, cancel, resume, audit manifest |
RunAttempt | (run_id, attempt_no) | Only fenced current lease may commit progress | Recovery, debugging, cost reconciliation |
AuditEvent | (tenant_shard, time_bucket, event_id) | Append-only; hash-chain/checkpoint integrity | Release/feature export and incident timeline |
Publish an artifact version
POST /v1/projects/prj_7/artifacts/req_42/versions If-Match: "v7:sha256:9f..." Idempotency-Key: "9da7..." { "base_version_id": "av_v7", "content": { "acceptance": [ ... ] }, "operation": "PUBLISH" } → 201 version av_v8 + analysis_generation ag_91 → 412 STALE_BASE with current etag + structured diff
Launch one logical run
POST /v1/work-orders/wo_81/agent-runs Idempotency-Key: "launch:wo_81:3" { "context_manifest": "cm_773", "capability_profile": "code-pr-only", "budget": { "usd_micros": 25000000 }, "provider_policy": ["private-a", "fallback-b"] } → 202 run ar_55; duplicate key returns ar_55 → 409 STALE_CONTEXT / 402 BUDGET_NOT_RESERVED
Retrying a command returns the original logical result. It must not publish a second version, reserve budget twice, or launch a second run.
High-level architecture
Keep synchronous authority small; let every expensive derivative be replayable and visibly stale.
Walk one requirement edit to a tested pull request.
The client edits through a realtime collaboration service, but publication goes to the authoritative API with an expected base version. In one transaction it stores the immutable version, advances the current projection, and writes an outbox record.
The event backbone fans out to impact analysis, search indexing, notifications, and policy evaluation. A human creates or updates a work order pinned to exact requirement and blueprint versions. The scheduler reserves quota and budget, snapshots an authorized context manifest, and leases an attempt to an isolated worker.
The worker retrieves only manifest-approved data through a policy gateway, invokes a model through a provider-neutral gateway, and calls tools with scoped capabilities. Tests and a PR are evidence artifacts; neither becomes approved truth until a human/release policy records a decision.
Forge logical architecture
Solid = authority · dashed = asynchronousTransactional outbox
Truth and “work must happen” commit together. Consumers are at-least-once and idempotent by event ID + analysis generation.
Immutable commit keys
Repository analysis is keyed by provider, repo, and commit SHA—not webhook order or mutable branch name.
Visible freshness
Search results and drift findings display index generation, source commit, coverage, and lag. “Partial” is a first-class state.
Deep dive: versioned provenance
The hard part is not drawing a graph. It is defining what an edge means when time, evidence, and authority change.
REQ-42 v7 is published. Forty dependent work orders are active and three agents opened PRs. A PM publishes v8 with a stricter safety constraint. What happens?
Publication of v8 is immediate and does not mutate v7. An impact job starts from edges incident to v7 and its stable element IDs, follows only policy-relevant edge types with cycle detection, and writes findings against analysis generation ag_92.
Running work retains its pinned v7 context manifest. Policy evaluates the changed field: a safety constraint is high severity, so affected runs move to STALE_PENDING_REVIEW before their next privileged tool step. Open PRs receive a visible stale-context check. A human may explicitly accept old-context output, but that exception is an approval event and the release still states it satisfies v7 unless new tests prove v8.
We incrementally compare stable requirement element IDs, not whole documents, to avoid invalidating unrelated work. Release gates query trace coverage: every v8 acceptance criterion needs a passing test and approved implementation edge at the pinned commit.
Why not put everything in a graph database and run the closure synchronously?
A graph engine may help traversal, but it does not define authority, version semantics, access policy, or a bounded query. I store the canonical edge fact with transactional identity and publish it through an outbox. A graph projection can be optimized and rebuilt. Closure is bounded by tenant, release snapshot, edge types, depth, node budget, and cursor; huge traversals return partial progress instead of blocking publication.
An edge is a claim, not a pointer
(source_version, source_span, target_version, target_span, type, asserter, evidence, confidence, policy, valid_from, superseded_by)
A model-suggested “implements” edge and a human-approved one are different facts even if endpoints match.
A release is a closed manifest
Artifact versions, commits, test runs, policies, approvals, tool receipts, and analysis generations are pinned and hash-addressed.
Never resolve “latest” during audit export; it changes underneath you.
| Edge type | Meaning | Who may assert | Impact direction | Release behavior |
|---|---|---|---|---|
DERIVED_FROM | Output used this exact source/span | Pipeline or human | Source change → output stale candidate | Evidence required |
IMPLEMENTS | Code/work realizes a requirement | Agent suggests; human/policy approves | Both directions | Approved edge required |
TESTS | Test exercises acceptance criterion | QA/agent proposal | Criterion → test | Passing pinned run required |
CONTRADICTS | Evidence conflicts with target claim | Analyzer or reviewer | Finding only | May block by policy |
SUPERSEDES | New version/decision replaces old | Authoritative workflow | Temporal navigation | Old remains auditable |
MENTIONS | Weak reference without implementation claim | Parser/search | Usually no invalidation | Never enough alone |
Consistency is chosen per invariant
OT or CRDT may merge text operations, but it must not merge approval state, publish two conflicting base versions, or turn an agent suggestion into authoritative content. Semantic workflow remains transactional.
Deep dive: durable agents
A run is a workflow with nondeterministic compute and ambiguous side effects—not a long HTTP request.
My laptop closes while an eight-hour agent is running. Then its worker dies. How does it continue safely?
The laptop owns only a subscription to progress. The durable run record, encrypted context manifest, budget reservation, checkpoints, and side-effect ledger live in the control plane. A scheduler grants an attempt a time-bounded lease with an epoch. The worker heartbeats and checkpoints at logical boundaries.
On missed heartbeats, the scheduler expires the lease and starts a new attempt from the latest valid checkpoint. Fencing means the old attempt cannot commit later. Cancellation increments a cancellation epoch; every tool gateway and checkpoint commit rejects stale epochs. Progress streaming may be down while execution continues.
The agent called an external ticket API. The ticket may have been created, but the response was lost. The retry is about to call again. Give me “exactly once.”
I cannot promise exactly-once across a system we do not control. Before the call, the tool gateway commits a REQUESTED receipt with a stable effect key such as run/step/tool/logical-target. It passes that key to providers supporting idempotency. After success it records the external ID and response hash.
If the outcome is unknown, the retry first queries by idempotency key or external correlation. If the provider offers neither, the run enters NEEDS_RECONCILIATION; a human verifies before retry. Compensation is a domain action, not a database rollback. We optimize for at-most-one harmful effect, not pretending transport semantics solve the business effect.
The preferred model provider is down. Can you fail over?
If tenant policy allows, a retry can route to a compatible provider after a capability and data-residency check. I record the provider, model/version, sampling parameters, normalized request hash, retrieved context IDs, and output. I claim functional evaluation and evidence—not byte-for-byte reproducibility. Privileged steps may require fresh approval after a provider change.
Logical run state machine
Attempt failure does not equal logical failureAmbiguous side-effect sequence
At-least-once transport, effect-aware workflowLease + fencing
A monotonically increasing lease epoch prevents a zombie worker from committing after failover.
Checkpoint contract
State is hash-addressed, encrypted, schema-versioned, and references immutable context—not raw mutable session memory.
Cost ledger
Reserve before scheduling; append usage by provider receipt; finalize or release reservation. Dashboard may lag the ledger.
Failure, trust, and revision
A strong candidate changes the design when the constraint changes. Use the scenario console to rehearse.
GitHub sends a push three times, then an older event. Mid-index, the installation is revoked. A force-push deletes commits already referenced by audit edges.
I verify the webhook signature against the installation secret, persist the delivery ID for dedupe, and enqueue by installation/repository/ref. A reconciler asks GitHub for the current ref, so delivery order is a hint—not truth. Parsing is keyed by immutable commit; duplicate work is harmless.
Revocation increments the integration grant epoch. Fetch and indexing workers re-check that epoch before every provider read and before publishing an index generation. New queries immediately fail policy checks even if a stale cache exists. Historical snapshots follow tenant retention policy: preserve encrypted audit references under legal hold or cryptographically erase content and leave a tombstoned hash/evidence envelope.
An EU bank wants a dedicated VPC, tenant-managed keys, no raw code in central logs, zero-retention models, and complete derived-data deletion. What changes?
I deploy the data and execution planes inside the EU tenant boundary and keep a minimal global control record containing no customer content. Keys are envelope-encrypted by the tenant KMS; model/tool egress is allowlisted by policy. Authorization runs both before retrieval and before the model/tool call, preventing a confused deputy.
Every chunk, embedding, prompt cache entry, checkpoint, trace, and evaluation example carries source lineage and tenant/key generation. A deletion job traverses lineage, tombstones live references, destroys data keys, rebuilds indexes, and produces a completion attestation. Legal hold preserves event metadata, approvals, hashes, and signer identity—not deleted plaintext.
One region fails with 2,000 jobs active. A customer then submits 20,000 migration jobs. Prevent split brain and starvation.
A single fenced scheduler authority per shard issues lease epochs from consensus-backed state. Failover requires quorum and increments the shard epoch; old-region workers cannot checkpoint or call privileged tools. The live event stream may disappear while safe runs continue.
Queues are hierarchical: tenant quota, workload class, then weighted fair scheduling with aging. I reserve capacity for interactive work, cap migration concurrency, and use per-tenant token buckets for model/tool budgets. I measure useful completion and queue age by tenant—not merely scheduler uptime.
Nominal run
Pinned context + valid lease + available budget are required before execution.
Primary risk
Nondeterministic output is accepted without evaluation or trace evidence.
Architecture revision
Model output becomes a suggestion; tests and human approval gate merge.
Trust boundaries
Human edge
- SSO / MFA
- device and session
- org/project role
- intent + approval
Control plane
- policy decision
- budget + leases
- immutable manifest
- audit identity
Retrieval
- tenant ACL
- classification
- source lineage
- prompt-injection labels
Sandbox
- ephemeral worker
- no ambient creds
- egress allowlist
- resource limits
External
- scoped OAuth
- effect idempotency
- provider retention
- receipt + reconcile
| Threat / failure | Prevention | Detection | Recovery |
|---|---|---|---|
| Cross-tenant retrieval | Tenant in partition key + policy-filtered query + tenant key | Canary documents, negative auth tests, access-anomaly alerts | Revoke grant, isolate index, incident audit, rebuild |
| Prompt injection in code | Retrieved text typed as data; tool capabilities independent of text | Policy-denied tool-call metrics; suspicious instruction classifier | Stop run, preserve trace, update skill/policy, re-evaluate corpus |
| Zombie worker after failover | Lease/shard epoch fencing at every commit and privileged tool call | Stale-epoch rejection count | Requeue from checkpoint; investigate duplicate attempts |
| Search ACL lag | Query-time and post-fetch authorization, not index filter alone | Revocation propagation SLO | Deny on uncertain policy; rebuild affected shards |
| Audit tampering | Append-only storage, integrity hash checkpoints, segregated writer role | Continuous chain verification | Fail closed for release export; restore replicated ledger |
| Deletion residue | Source-lineage IDs and tenant key generation on every derivative | Deletion coverage query + sampled forensic scan | Crypto-erase, rebuild, attestation, incident if SLO breached |
Classic traps to name before they name you
“Use a graph DB.”
A product choice without typed edge semantics, version identity, traversal budget, or authorization is not a design.
“Exactly once.”
External business effects need idempotency receipts, reconciliation, and sometimes a human—not a messaging slogan.
“Temperature zero.”
Provider/version changes, hidden infrastructure, and nondeterminism prevent byte-identical replay. Preserve observable evidence.
“CRDT everything.”
Text convergence is not semantic approval. Publish, money, leases, and permissions need transactional authority.
“Cache permissions.”
Revocation must beat stale cache. Deny when policy freshness is unknown; authorize after retrieval too.
“Retry the agent.”
Without attempt identity, checkpoint, effect ledger, cancellation fence, and budget reconciliation, retry creates harm.
Evaluation, rollout, recap
Close by proving the system changes outcomes safely, not by listing dashboards.
How do you know this system is useful and safe? Give me your rollout and final summary.
I separate platform health from product quality. Health includes API SLO, index lag, queue age by tenant, lease recovery, cancellation latency, and missing receipts. Quality includes trace coverage, orphan rate, drift precision/recall, reviewer burden, requirement-to-test coverage, accepted work-order cost, escaped defects, and rollback rate.
I roll out in four gates: read-only repository indexing; advisory provenance and drift with measured reviewer feedback; durable agents limited to sandbox/test/PR; then policy-gated automation by tenant and action. Every gate has a kill switch, shadow comparison, and rollback.
In one sentence: Forge keeps immutable, tenant-scoped truth in a small transactional control plane; projects it asynchronously into search and impact views; and runs fallible agents through a durable, fenced, budgeted, evidence-producing workflow where humans retain authority.
Control plane health Example scorecard
Product quality Measure accepted outcomes
Illustrative values only. A useful metric always defines unit, window, slice, owner, and action threshold.
Observe
Read-only repo indexing. Validate ACL, freshness, cost, and parser coverage. No workflow effects.
Advise
Provenance suggestions and drift findings. Capture dismissal reasons and calibrate thresholds by slice.
Execute safely
Agents run tests and open PRs in sandboxes. Human merge required. Chaos-test leases and receipts.
Gate by policy
Enable selected low-risk automations per tenant, with budgets, approvals, kill switches, and rollback.
Your 10-point closing checklist
- Define authoritative truth and human boundaries.
- Separate stable identity from immutable version.
- Pin releases and runs to exact manifests.
- Commit outbox work with truth.
- Let derived indexes converge visibly.
- Model logical runs separately from attempts.
- Fence leases, cancellation, and side effects.
- Authorize retrieval and tool use independently.
- Measure outcome quality and tenant fairness.
- Roll out from observe to advise to gated action.
when all invariants land
Say the final candidate paragraph aloud. Then name the three principal trade-offs: eventual impact/search, no global exactly-once, and audit replay based on observable evidence rather than identical model text.