« Phase 17 README · Hitchhiker's · Deep Dive · Principal Deep Dive · Core Contributor · Staff Notes
Phase 17 Warmup — The Enterprise Agentic Platform, End to End
Who this is for: you've done the track. Now you assemble it. This warmup walks the request lifecycle you build in the lab, explains why each layer sits where it does, and frames the whole thing the way a Staff/Principal system-design interview expects.
Table of Contents
- From mechanisms to a platform
- The request lifecycle, layer by layer
- Why the order matters
- The cross-cutting concerns
- Trust boundaries in the composed system
- What's minimal here vs production
- Reasoning about failure modes
- Lab walkthrough
- Success criteria
- Interview Q&A
- References
1. From mechanisms to a platform
Every phase so far answered "how does X work?" This one answers "how do they fit together?" — and
that question is where Staff and Principal engineers earn their title. A platform is not a pile of
features; it's a set of layers composed in a specific order with explicit trust boundaries
between them, where each layer's guarantee stacks onto the next. The lab builds exactly this: one
handle(token, question) that a request flows through, top to bottom, and you can turn any layer
off to watch a specific attack or failure get through. That toggle-and-observe is the whole
lesson.
2. The request lifecycle, layer by layer
A request (a token + a question, possibly with untrusted content the agent will read) flows through:
- Authenticate + resolve tenant (Phase 13). Verify the signed token; the tenant identity comes from the token, never the request body. A forged token dies here.
- Authorize + quota (Phase 13, 14). RBAC with default-deny decides if this principal may act; a per-tenant token bucket enforces fair use. A viewer or an over-quota tenant dies here.
- Input guardrail (Phase 10). Untrusted content (a fetched page, a pasted document) is scanned for injection; a hit is quarantined. The indirect-injection attack dies here.
- Assemble context within a budget (Phase 4). System prompt + retrieved grounding + question, packed to fit the token budget, pinned parts always present.
- Retrieve grounding, tenant-scoped (Phase 5/6). The corpus search is scoped to the caller's tenant, so one tenant can never ground on another's documents.
- Run the agent (Phase 1/2), metered and traced (Phase 14). The ReAct loop with validated tool calls produces an answer; every token and span is recorded.
- Output guardrail (Phase 10). The answer and its actions are scanned for exfiltration — a leaked secret or an exfil URL. A hijacked-agent leak dies here.
- Eval gate (Phase 11). Sampled requests are checked for groundedness/safety; an ungrounded hallucination is caught before it reaches the user.
- Audit (Phase 13). Every terminal path logs metadata (who, what, outcome) — never secret content — for incident response and compliance.
Nine steps, ten phases, one function. That's the platform.
3. Why the order matters
The order is not arbitrary; each step depends on the ones before, and swapping them opens a hole:
- Authenticate before authorize. You can't decide what a principal may do until you know who
they are — and you must derive identity from the verified token, not trust a claimed
tenant_id. - Authorize/quota before doing expensive work. Reject unauthorized or over-quota requests before you spend tokens on retrieval and the model. Cheap checks first.
- Input guardrail before the agent. Quarantine injection before the untrusted text reaches the model — after is too late, the model already read the command.
- Retrieve tenant-scoped, always. Isolation is threaded through the query, not bolted on after; a retrieval that isn't tenant-scoped is a cross-tenant leak regardless of later checks.
- Output guardrail + eval before returning. The last gates: never return an answer you haven't scanned for exfiltration and (sampled) checked for grounding. Output guarding is your final line.
- Audit on every path. Blocks and successes alike — the audit log is the incident-response and compliance substrate, useless if it only records the happy path.
Being able to explain why authenticate precedes authorize or why the input guard precedes the agent is precisely the reasoning a senior interview is testing.
4. The cross-cutting concerns
The five load-bearing truths from Phase 00 aren't a step — they're everywhere:
- Reliability compounds (Phase 0). The step budget, retries, and (in production) the durable
engine (Phase 8) keep the agent loop reliable enough to ship;
0.95^ndecides how many autonomous steps you allow before a checkpoint or a human. - Security is architectural (Phase 9/10/13). The trust boundary, least-privilege tools, sandboxing, guardrails, and tenant isolation are layers of code, not a prompt paragraph.
- Cost/latency are engineered (Phase 0/14). The cost meter, model routing, caching, and p95
budgets are instrumented from day one; the platform reports
$/resolved-task, not just$/request. - Evaluate or don't ship (Phase 11). The eval gate and (in production) behavioral regression suites in CI are what let you change the system without silently regressing quality.
- Observability (Phase 14). Traces, metering, and audit make the platform debuggable and auditable — you can answer "what did this agent do, for whom, at what cost?" for any request.
A platform that nails the lifecycle but skips these is a demo. Nailing both is the job.
5. Trust boundaries in the composed system
Draw the boundaries explicitly, because that's where every security property lives:
- Outside → gateway: the token is untrusted until verified; the question and any pasted content are untrusted forever (they may carry injection).
- Gateway → agent: the agent receives tenant-scoped, guardrail-checked context; it can only call allow-listed tools; its output is scanned before it leaves. The model is treated as an untrusted component producing proposals your code validates and gates.
- Agent → tools/data: least privilege and tenant scoping mean a hijacked agent has a tiny blast radius — it can't reach another tenant's data or a tool it wasn't granted.
The composed system is a series of nested trust boundaries, each narrowing what the untrusted parts (the outside input, the model's output) can touch. That mental picture is the senior security answer.
6. What's minimal here vs production
The lab's components are teaching miniatures; here's the honest mapping to production so you can speak to both:
| Lab | Production |
|---|---|
| hmac token | real OAuth2/OIDC + JWT, short-lived, rotated |
| lexical retrieve | hybrid dense+BM25+rerank (P5), GraphRAG/RAPTOR (P6), a real vector DB |
| scripted agent | the ReAct/ReWOO runtime (P1) calling a real LLM via MCP tools (P3) |
| in-memory store | Postgres w/ row-level security, per-tenant vector namespaces |
| regex guardrails | Llama Guard / classifiers plus the architectural controls |
is_grounded heuristic | LLM-as-judge + human-calibrated eval (P11), regression suite in CI |
Span dataclass | OpenTelemetry GenAI spans exported to a tracing backend |
| single process | durable workflows (P8), a sandbox (P9), autoscaling services (P12) |
The lifecycle and boundaries are the same at both scales; only the components get heavier.
7. Reasoning about failure modes
A senior engineer designs by asking "how does this break?" For each layer: what happens if it's misconfigured, overloaded, or bypassed? The auth layer fails closed (a bad token is rejected, not allowed). The quota protects downstream LLM rate limits. The input guard's false negatives are why you also have least privilege and the output guard (defense in depth). The eval gate is sampled, so a rare bad answer can slip — which is why you also have output guarding and human review on high-impact paths. Naming these — and the fact that no single layer is trusted to be perfect — is the difference between a design that survives contact with production and a demo.
8. Lab walkthrough
Open lab-01-capstone-integration/. The dataclasses and
trivial helpers are given; you implement verify_token, authorize, TokenBucket.allow,
TenantStore.docs_for, the two guardrails, retrieve, assemble_context, is_grounded, and —
the main event — AgentPlatform.handle, the ordered lifecycle. Follow the step list in the
handle docstring exactly; each blocked_by value maps to a test. Run LAB_MODULE=solution pytest -v first to see the target, then match it, then read solution.py's main() — five
scenarios (benign, injection, cross-tenant, forged token, quota) that exercise every terminal path.
9. Success criteria
- You can draw the lifecycle from memory and name each layer's phase.
-
Your
handleblocks at the right layer for each attack and audits every path. - You can explain why the order matters and where each cross-cutting concern lives.
- You can map every miniature to its production counterpart.
-
All 19 tests pass under
labandsolution.
10. Interview Q&A
Q: Design an enterprise agent platform. A: Start with the request lifecycle:
authenticate + resolve tenant from a verified token → authorize (RBAC default-deny) + quota →
input guardrail on untrusted content → tenant-scoped retrieval + budgeted context → the agent
runtime (validated tools, step budget, durable if long-running) metered and traced → output
guardrail → eval gate → audit. Then layer the cross-cutting concerns: reliability (0.95^n,
retries, durability), security (trust boundary, least privilege, isolation), cost/latency
(routing, caching, p95, $/resolved-task), evaluation (golden sets, regression gates), and
observability (traces, metering, audit). I'd call out the trust boundaries explicitly and the
failure mode of each layer.
Q: Why does the input guardrail come before the agent and the output guardrail after? A: Injection has to be caught before the untrusted text reaches the model — after, the model already read the command. The output guardrail is the last line before anything leaves, catching a leak from an agent that got hijacked anyway (defense in depth). Both exist because neither alone is sufficient.
Q: Where does multi-tenant isolation live, and what's the #1 leak? A: It's threaded through
every data access from the verified token — row-level scoping on the store, per-tenant namespaces
on the vector index, tenant-keyed caches, per-tenant secrets. The #1 leak is a shared vector
index: if retrieval isn't scoped by tenant, one customer grounds on another's documents. You
never trust a tenant_id from the request; you derive it from the signed token.
Q: What would you add to make this production-grade? A: Real OAuth/JWT, a durable engine so crashed requests resume and high-impact actions pause for human approval, MCP tools in a sandbox, hybrid+graph retrieval on a real vector DB, LLM-as-judge evals with a regression suite in CI, model routing + semantic caching for cost, and OpenTelemetry tracing to a backend — plus SOC2-grade audit and data-residency controls. The lifecycle stays the same; the components get heavier.
11. References
- system-design/01-enterprise-agent-platform.md — the full-scale version of this lab.
- Anthropic, Building Effective Agents (composition patterns). https://www.anthropic.com/research/building-effective-agents
- AWS SaaS Lens / multi-tenant SaaS architecture (silo/pool/bridge). https://docs.aws.amazon.com/wellarchitected/latest/saas-lens/
- OpenTelemetry GenAI semantic conventions. https://opentelemetry.io/docs/specs/semconv/gen-ai/
- OWASP Top 10 for LLM Applications. https://owasp.org/www-project-top-10-for-large-language-model-applications/
- The rest of this track — Phases 00–16 are the components this capstone composes.