Skip to content
Kiran
← Work

32 domain agents · SAP HANA · three surfaces

Enterprise NL-to-SQL Agent Platform

A hub-and-spoke agent platform where the hub has no database tools. The orchestrator classifies and delegates; only domain agents touch the warehouse. That one boundary is simultaneously a security property (a routing mistake cannot become a data leak), and a context-economy property, because the router never carries the schema. Around it sits the part that took longest to get right: a three-tier model registry that ops can retune without a deploy, a read-only guard at the connection boundary, a role-scoped SQL validator that shares its parsing patterns with that guard so the two cannot drift, and loop guards that exist because an agent once burned roughly a million tokens retrying one failing query.

2024–2026agenticplatformsecuritydataeconomicsevaluation

What I owned

Primary architect. I owned the end-to-end system design: topology, orchestration, agent design, the model-tier and cost architecture, the security boundaries, the middleware contract, the evaluation approach and the deployment strategy, and set the technical direction the platform was built to. Other engineers implemented domains and surfaces within that architecture; the boundaries they built against are the ones I drew.

Domain agents in production
32codeDomain agents in production
Evaluation scenarios
411codeEvaluation scenarios
Domain skill packs
37codeDomain skill packs
Built onLangGraph with a deep-agent frameworkVertex AI model registrySAP HANAA sandboxed JavaScript interpreterCloud Run and Cloud Build

The problem

What was actually wrong

Planners and analysts needed answers about orders, shipments, manufacturing backlog, material attributes, purchase-order timelines, build operations, recommits, scheduling and lead times. All of it lived in a warehouse that required SQL and schema knowledge, so questions queued behind the small number of people who had both.

Natural-language-to-SQL is a well-known demo and a poorly-known production system. The demo problem is generating a query. The production problems are different: keeping a schema large enough to answer real questions out of every agent's context window, ensuring a generated query can never write, ensuring one user cannot see another's scope, and stopping an agent that has started failing from failing expensively.

Before this existed

Analyst-authored SQL and spreadsheet reports, with a queue in front of the people who knew the schema.

Constraints

The conditions the design had to hold under

Constraints are the interesting part of an architecture. Without them any diagram looks reasonable.

A ~388-column foundation table
The central table alone has around 388 columns. Any design that puts the schema in the model's context pays for it on every single turn, in every agent.
The warehouse must never be written to
Read-only cannot be a prompt instruction or a tool convention. It has to be a property of the connection.
Answers are role-scoped
Different roles may see different columns and different resources. The same question from two users can legitimately have two different answers, and neither may leak the other's.
Three surfaces, one platform
A web application, an enterprise chat bot and an external API all address the same agents, so nothing user-facing can live inside any one surface.

My role

Primary architect. I owned the end-to-end system design: topology, orchestration, agent design, the model-tier and cost architecture, the security boundaries, the middleware contract, the evaluation approach and the deployment strategy, and set the technical direction the platform was built to. Other engineers implemented domains and surfaces within that architecture; the boundaries they built against are the ones I drew.

Designed

  • The hub-and-spoke topology and its load-bearing rule: the orchestrator holds no database tools, so a routing mistake cannot become a data leak
  • The orchestration model (classify, delegate, synthesise), and the typed shared blackboard that moves cross-domain findings without re-passing them as text
  • The domain-agent contract: a manifest plus registry declaring skills, capabilities and interpreter access, so a domain is a described unit rather than wired-in code, and every domain is also addressable as a standalone graph
  • The guard middleware every agent inherits: identical-call loop guard, per-turn tool-call budget, filesystem allow-list over source, configuration, credentials and prompts
  • The three-tier model registry with per-tier and per-agent environment overrides, so model choice is an operations lever rather than a release
  • The layered security model: engine-level read-only at the connection, role-scoped SQL validation sharing its parsing patterns with that guard so the two cannot drift, and log sanitisation
  • The integration surface: one agent layer behind a web application, an enterprise chat bot and an external API, with nothing user-facing living inside any one surface
  • The evaluation approach: scenario suites that declare the user's roles, so authorization behaviour is exercised as part of answer quality rather than tested separately
  • The deployment strategy: containerised serverless with runtime database failover, so a dead host recovers without a redeploy

Built

  • Reference implementations of the domain contract that the rest of the domains were built against: inventory statistics, excess-and-obsolete, forecasting and transit-time prediction
  • The inventory-statistics domain in full: fiscal period bucketing, point-in-time routing, per-period provenance, multi-version routing, cost-aware routing and snapshot-freshness transparency
  • The excess-and-obsolete domain, including exclusion guards that deliberately retain null item types
  • Runtime database failover and the model-registry resolution path

Led

  • Set the guardrail conventions every agent on the platform inherits, and the fail-closed-on-ambiguity, fail-open-on-infrastructure rule they encode
  • Reviewed domain and surface work against the architecture, which is where a contract either holds or quietly stops being one
  • Audited the platform's own evaluation suite before allowing it to gate a cost programme, and published the result
  • Held the line on scope in review, including removing unrelated changes from my own pull requests

Architecture

How it is put together

One orchestrator, 32 domain agents, and a hard separation between them. The orchestrator routes and synthesises; the domains hold the schema, the tools and the database access. Every domain is also registered as a standalone graph, so the same code serves as both a spoke and a directly addressable specialist.

The same architecture, in prose

A question arrives from one of three surfaces: a web application, an enterprise chat bot, or an external API.

The orchestrator runs on the highest model tier and holds no database tools at all. It classifies the question and delegates.

Domains are discovered from a registry, each described by a manifest that declares its skills, its capabilities and whether it may use the calculation interpreter.

The selected domain agent runs on the middle tier, loads the skill packs its manifest declares, and authors SQL, either as raw SQL against a known schema or through hand-written typed capabilities, depending on the domain.

Cross-domain findings move through a typed shared blackboard rather than being re-passed as text through the orchestrator.

Guard middleware wraps every agent: an identical-call loop guard, a per-turn tool-call budget, and a filesystem allow-list that blocks source, configuration, credentials and system prompts.

Before execution, a role-scoped access validator checks the statement against the user's permitted columns and resources.

At the connection boundary, an engine-level listener rejects any statement that is not a read.

Results return to the domain agent, which answers in business language. SQL is scrubbed before it reaches any log, and the conversation is written to an audit table.

History compaction runs on the lowest tier, its only consumer, keeping long conversations affordable.

Every path, written out (3)· the walkthroughs above, as text

A planner asks a question

"How much of the current-quarter backlog is blocked on materials?"

  1. 01

    Classify and delegate, with no schema in context

    The orchestrator, on the high tier, identifies the domains involved and delegates.

    It holds no database tools, so it never loads the schema. The router stays cheap and a routing error stays a routing error.

  2. 02

    Construct the domain from its manifest

    The registry builds the domain agent with the skills, capabilities and interpreter policy its manifest declares.

    Domains are described rather than wired, which is why the platform grew to 32 of them without the orchestrator growing with it.

  3. 03

    Author the query on the middle tier

    The domain agent, holding only its own schema and skills, produces SQL or calls a typed capability.

    Narrower context and a narrower task, so the cheaper tier is genuinely sufficient rather than a compromise.

    Fails by: Wide tables produce mis-named columns and wrong joins. Each failure is a round trip, which is why the guards below exist.

  4. 04

    Check against the caller's role

    The access validator checks columns and resources against the role's policy.

    Restricted fields return a sentinel the agent must explain, rather than being silently omitted from an answer that then reads as complete.

    Fails by: A restriction becomes part of the answer: the user is told what they could not see.

  5. 05

    Refuse anything that is not a read

    An engine-level listener rejects non-read statements before they reach the database.

    At the connection, not the prompt. It applies to code paths that do not exist yet.

  6. 06

    Answer in business language

    Rows come back; the agent answers as a planner would want it phrased, with the calculation done in the sandbox where arithmetic is involved.

    Speak to planners about forecasts, not to statisticians. Evaluation scenarios forbid internal SQL and system identifiers from ever appearing in a final answer.

  7. 07

    Log it, scrubbed

    The turn is written to the audit table with SQL sanitised.

    An audit trail that itself leaks query internals into logs is a new disclosure surface rather than a control.

Failure path: one million tokens on one bad query

An agent hits a failing query and retries it. Three production threads did this in a single week, one of them burning on the order of a million tokens.

  1. 01

    The query fails, and the agent tries again

    The model re-issues the same statement with the same arguments, reading the same error, indefinitely.

    Nothing in the loop distinguishes a retry that might succeed from one that cannot.

  2. 02

    The recursion limit is the only backstop

    It runs until the framework's recursion limit fires, long after the money is spent.

    A step limit bounds correctness, not cost. Those are different budgets and need different instruments.

  3. 03

    Short-circuit the Nth identical call

    A loop guard short-circuits repeated calls with identical tool and arguments, excluding tools that legitimately repeat.

    Cheap, deterministic, and it catches the exact-repetition case completely.

  4. 04

    And a budget for the agent that varies its calls

    A separate per-turn tool-call budget caps total non-excluded calls, for the failure mode where the agent invents new failing calls rather than repeating one.

    The loop guard is blind to an agent paraphrasing itself. Two guards because there are two failure modes, not because one needed a bigger number.

Failure path: a dead database host

A warehouse host goes down. The platform previously needed a redeploy to recover.

  1. 01

    The host stops answering

    Connections to the configured host fail.

    Host identity was resolved once at startup, so the process was pinned to a host that no longer existed.

  2. 02

    Every domain is down at once

    All 32 domains share the engine, so a single host failure is a total outage.

    Shared infrastructure concentrates both efficiency and blast radius. Here it concentrated the blast radius.

  3. 03

    Fail over at runtime

    Host selection moved into the runtime, so a dead host is replaced without redeploying.

    Recovery time went from a release cycle to a reconnect. The best reliability work is usually removing a human step from the recovery path.

What changes as load grows· the scale stages, as text

One question

code

1 thread · 1 domain touched · 1 hub round trip

The path the code actually takes for a single question: the hub reads the request, the registry resolves one domain, the validator scopes the query to the asker's role, and HANA answers. Every guard is on and costs nothing measurable at this size.

Gives first: Nothing structural. End-to-end latency is one routing hop, one domain hop and one warehouse query, and the warehouse query dominates.

A planning team

modelled

tens of concurrent threads · several domains per question

Multi-domain questions start arriving, so a single request fans out to several domain agents and their findings have to be reconciled. The blackboard stops being an optimisation and starts being the thing that keeps the hub's context from carrying every intermediate result. Compaction runs on most threads rather than a few. Tier routing matters, because the cheap tier is now absorbing the volume the expensive tier used to see.

Gives first: Hub context. Each hop re-consumes the request, the agent outputs, the tool results and the task state, so the token cost of a question grows with the number of domains it touches rather than with the size of its answer.

The whole supply-chain org

modelled

hundreds of concurrent threads · long-lived conversations

The shape breaks before the infrastructure does. Hub-and-spoke is correct for bounded question answering and wrong for persistent collaboration: every meaningful interaction still returns through one model, which is a serial bottleneck no amount of horizontal capacity removes. Guards get exercised constantly rather than occasionally, so the loop guard and call budget become load-bearing. The evaluation suite has to run per-domain rather than end-to-end, or a regression in one domain is invisible in the aggregate.

Gives first: The topology. This is the point where I would put a collaboration control plane beside the hub rather than widen the hub. Specialists become persistent participants instead of transient tools, and the serial return through one model goes away.

Decisions

The calls I would defend

Each one with the alternatives I rejected, what the choice cost, and how it turned out.

Decision

Routing and synthesis live in the hub; every database tool lives in a domain agent.

Context

The obvious design gives the orchestrator a general query tool so it can answer simple questions itself.

Alternatives, and why not

  • Give the orchestrator a general SQL tool for simple questionsIt would need the schema, and the central foundation table alone has around 388 columns. Every turn of every conversation would pay for it, including turns that never touch the database.
  • Give the orchestrator a restricted read tool over a small curated viewIt creates a second, weaker path to the data with its own policy surface. Two authorization paths is one too many.

Rationale

One boundary buys two properties. Context economy: the router never carries schema. Security: a routing mistake cannot become a data leak, because the router has no way to read anything.

What it cost

An extra hop for questions a hub could have answered directly, and cross-domain work needs a shared findings channel rather than the hub holding state.

Outcome

The platform reached 32 domains without the orchestrator's context growing with it.

What it moved in the diagram

What broke

Failures, and what they changed

Every one of these is a thing that went wrong in a system I own. They are here because the architecture is largely a record of them.

Roughly a million tokens on a single failing query

What happened
An agent retried the same failing statement until the framework's recursion limit fired. Three production threads hit this in seven days.
Root cause
The only backstop on a stuck agent was a step limit, which bounds correctness rather than cost. Nothing distinguished a retry that could succeed from one that could not.
What I did
A loop guard that short-circuits the Nth identical tool call with identical arguments.
What changed in the architecture
Guard middleware became part of the standard agent assembly, so every domain inherits it rather than opting in.
What it taught me
Correctness limits and cost limits are different budgets. A system with only the first will discover the second on an invoice.

The loop guard missed the agent that varied its calls

What happened
An agent that kept inventing new failing calls, rather than repeating one, ran unbounded past a guard designed for exact repetition.
Root cause
Keying on identical tool and arguments catches only the least creative failure.
What I did
A separate per-turn budget on total non-excluded tool calls.
What changed in the architecture
Both guards exclude tools that legitimately repeat (task updates, subagent dispatch, read-only probes), so the guards do not become the outage.
What it taught me
Count kinds of runaway, not repetitions. Every guard you add teaches the next failure how to avoid it.

A dead database host required a redeploy

What happened
Host identity was fixed at startup, so a warehouse host failure took all 32 domains down until a release restored service.
Root cause
Connection configuration was resolved once and never revisited by the running process.
What I did
Runtime failover so a dead host is replaced without redeploying.
What changed in the architecture
Recovery moved out of the release path.
What it taught me
Measure reliability work by how many human steps it removes from the recovery path, not by how much redundancy it adds.

The evaluation suite was large and hollow

What happened
Before allowing the suite to gate a cost programme, I audited it. Of 271 assertions in the legacy layer, 265 asserted nothing. The suite returned green regardless of what the system did.
Root cause
Scenario count had been treated as coverage. A suite grows by adding files, and nothing in that process checks that the assertions bind.
What I did
Published the finding and made the conclusion explicit: never gate on the legacy suite. Real gating moved to the assertions that were verified to bind.
What changed in the architecture
Evaluation of the evaluation became a prerequisite for any programme that depends on it.
What it taught me
A green safety net you have not audited is worse than no safety net, because it is spent as confidence.

The schema payload crowded out the context it was supposed to serve

What happened
Authoring raw SQL against a foundation table of around 388 columns forces an ever-growing schema description into every agent's context, and mis-named columns and wrong joins each cost a full round trip.
Root cause
The two available patterns sit at opposite ends of a cost curve: raw SQL is cheap to maintain and expensive at runtime; hand-written typed capabilities are cheap at runtime and expensive to maintain, at roughly 1,600 lines for around nine functions in one domain.
What I did
Quantified both costs in tokens, latency and maintenance hours rather than arguing them, and scoped a declarative semantic layer as the third option.
What changed in the architecture
In-flight. The platform still runs both patterns, chosen per domain by how stable that domain's questions are.
What it taught me
When both available options are defensible and both fail at scale for different reasons, the answer is usually a third thing, but only after the two failures are measured.

Column casing broke the what-if simulator

What happened
The simulator failed on the warehouse's column casing conventions.
Root cause
Case handling assumed the source system's convention rather than the warehouse's.
What I did
Fixed the casing handling, and later replaced the simulation approach entirely with a structural statistical simulation.
What changed in the architecture
Forecasting moved from a model-driven what-if to a structural simulation whose behaviour is explainable to a planner.
What it taught me
The bug was casing; the real finding was that the feature could not be explained to the people using it. Speak to planners about forecasts, not to statisticians.

A metric was inconsistent across the inventory domain

What happened
A review of product-family reporting surfaced the same metric computed inconsistently in different paths.
Root cause
Metric semantics lived in each code path rather than in one definition, so paths diverged as each was extended.
What I did
Hardened metric consistency across the domain, with per-period version provenance so a number can be traced to the snapshot it came from.
What changed in the architecture
Snapshot freshness became visible in answers rather than implicit, and multi-version routing made point-in-time questions answerable.
What it taught me
In a reporting system, an inconsistent metric is indistinguishable from a wrong one to the person reading it.

Agents invented fiscal period labels

What happened
Asked about history, agents produced plausible fiscal-week labels rather than discovering which periods actually existed.
Root cause
Nothing required the agent to establish what was available before answering about it.
What I did
Encoded as an evaluation grading rule that grades trajectory: the agent must discover available cycles before answering, not just arrive at a correct-looking answer.
What changed in the architecture
Trajectory rules joined outcome assertions in the scenario format.
What it taught me
Grading only the answer rewards a model that guesses well. Grading the path is how you catch the guess that happened to be right.

Evaluation

How I knew whether it worked

The suite is 411 scenarios across per-domain files with a shared harness. The more useful thing I can say about it is that I audited it before trusting it, and it failed the audit.

Lead with the audit, not the count

Before letting the suite gate a cost programme, I checked whether its assertions bound to anything. 265 of 271 assertions in the legacy layer asserted nothing. The scenario count was a vanity metric; the audit is the actual engineering.

Scenarios carry an identity

Each declares the user's roles, so the suite exercises authorization behaviour rather than only answer quality. An agent that silently omits restricted columns produces an answer that reads complete and is wrong. Only an identity-bearing scenario catches that.

Deterministic assertions before graded ones

Required and forbidden content, source and duration bounds, and leakage checks run first and cost nothing. Graded rules run only where a scenario declares a rubric.

Security enforced as a test

Scenarios forbid internal SQL fragments and warehouse system identifiers from appearing in a final answer. A leak becomes a failing test rather than a filter someone has to maintain.

Rules grade trajectory, not just outcome

"Determines which cycles are available rather than fabricating a period label" grades how the agent got there. This is the part of agent evaluation that generalises, and the part most suites skip.

The judge is a different family from the model under test

Held outside the tier system precisely so a tier change cannot silently make a model its own judge.

Security and safety

What the system refuses to do

Four independent layers, each at the lowest level that can enforce its property, plus the deliberate coupling that keeps two of them from disagreeing.

No database tools above the domain boundary

The orchestrator cannot read the warehouse, so a routing error cannot become a disclosure. The security property and the context-economy property are the same boundary.

Read-only at the connection

An engine-level listener rejects non-read statements. Not a prompt rule, not a tool convention, but a property of the connection that every future code path inherits.

Role-scoped resource policy

Permitted columns and resources per role, with a restricted sentinel the agent must explain rather than silently omit.

Shared parsing, deliberately

The read-only guard and the access validator strip identical syntax from one shared module, because two security checks parsing the same input independently will eventually disagree.

Default-deny filesystem

Agent filesystem tools are constrained to an allow-list; source, configuration, credentials, data and system prompts are unreachable, and writes are confined to a scratch directory. Agents cannot modify the skill packs that define their own behaviour.

Sanitised logs and an access audit

SQL is scrubbed before logging, so the audit trail is not itself a disclosure surface. An access-scoping audit was run against the role policy rather than assumed correct.

Impact

What changed, and how it is known

Every figure carries its basis. Nothing here is rounded up, and nothing modelled is presented as a result.

32code
Domain agents in production
411code
Evaluation scenarios
37code
Domain skill packs
3code
User-facing surfacesWeb application, enterprise chat bot, external API.
~388code
Columns in the central foundation table
~1Mobserved
Tokens burned by one runaway retry loop
3observed
Production threads hitting that loop in 7 days
265 / 271observed
Legacy eval assertions that assert nothing
Business
Supply-chain questions that previously queued behind the people who knew the schema are answered directly, in the surface the asker already uses.
Engineering
Domains are described by a manifest and discovered by a registry, so the platform is a framework rather than an application, which is why it reached 32 domains without the orchestrator growing with it.
People using it
Planners get answers phrased in their own vocabulary, scoped to what their role may see, with restrictions explained rather than silently applied.

Leadership and hindsight

What I influenced, and what I would change

Technical leadership

  • Audited the platform's own evaluation suite before allowing it to gate a cost programme, published the negative result, and recommended against gating on it, against my own interest in the suite looking good.
  • Established the guardrail conventions every agent on the platform inherits, so agent authors get the loop guard, the call budget and the filesystem boundary without knowing they exist.
  • Made model routing an operational lever rather than an engineering ticket, which is what allowed cost work to happen at all.
  • Held scope discipline in review, including removing unrelated changes from my own pull requests rather than letting them ride along.
  • Wrote domain knowledge into files a supply-chain specialist can read and correct, instead of into prompts only an engineer can change.

What I would do differently

  • Hub-and-spoke is the right shape for bounded question answering and the wrong shape for persistent collaboration. Every meaningful interaction returns through one model, which is a serial bottleneck; the hub re-consumes the request, the agent outputs, the tool results and the task state on each hop; and specialists behave like transient tools rather than persistent participants. I would not extend this topology into multi-agent group work; I would put a collaboration control plane beside it.
  • The raw-SQL versus typed-capability choice should have been resolved with a declarative semantic layer earlier. Both existing patterns are defensible and both fail at scale for opposite reasons (one on runtime token cost, one on linear hand-written maintenance), and running both indefinitely means paying both failure modes.
  • 411 scenarios looked like coverage for longer than it should have. The lesson I actually took is to assert on the assertions: a test that cannot fail is a line in a report, not a safeguard.
  • The tier system is right and its exceptions are under-documented. Three models sit deliberately outside it, and that intent lives in too few places for a system this size.

Go deeper

The detail, for people who want it

Collapsed by default. The case study stands without any of it.

Why domains vary in shape, and the third option

Two patterns coexist in the platform, deliberately, at opposite ends of a cost curve.

Raw SQL against a known schema is cheap to maintain and expensive at runtime: the model authors queries against a foundation table of around 388 columns, mis-names columns, picks wrong joins, and emits invalid syntax. Each failure is a round trip, and the schema payload grows in every agent's context to try to prevent it.

Hand-written typed capabilities are the inverse: validated arguments, pre-tested SQL, a compact tool schema and no schema dump, but around 1,600 lines for roughly nine functions in a single domain. That is linear hand-work that does not scale, and it crowds out the engineering bandwidth and agent context wanted for actions and cross-system integration.

The resolution is a declarative semantic layer: describe the measures, dimensions and joins once, and generate both the compact tool surface and the query. The reason this is a decision rather than an opinion is that both costs were measured in tokens, latency and maintenance hours first.

Why every domain is also a standalone graph

Each domain is registered both as a spoke beneath the orchestrator and as a directly addressable graph in its own right.

That means the same code serves two consumers: the general assistant, and a caller who already knows they want the scheduling specialist and does not want to pay a routing hop to say so.

It also makes evaluation cleaner. A per-domain scenario addresses the domain graph directly, so a failure is unambiguously the domain's rather than the router's.

The cost is that every domain must be independently constructible from its manifest, with no hidden dependency on orchestrator state. That constraint is what kept the domains genuinely modular as the count grew.

The blocking-detector detail behind import-time path resolution

The filesystem allow-list resolves its permitted paths at import time, which looks like premature initialisation and is not.

Resolving a relative path to a real path implicitly reads the process working directory. The development server enables a detector that correctly flags working-directory reads as event-loop-blocking calls.

Resolving the allow-list before the event loop exists avoids the call entirely at request time. The alternative is either a blocked-loop warning on every path check or a thread-pool hop for a string operation.

It is a small thing, but it is the kind of small thing that decides whether a security control is cheap enough to leave on everywhere.

What restricted looks like to a user

When a role may not see a column, the validator returns a restriction sentinel rather than dropping the column from the result.

This is deliberate. A silently omitted column produces an answer that reads as complete, and the user has no way to know they are looking at a partial picture.

The agent is required to state the restriction in the answer. An evaluation scenario running under that role checks that it does.

The general rule the platform follows: degradation must be visible at the point of use, not just in a log nobody reads during the decision.

Stack

What it is built on, and why that

A technology list without reasons is a list of things I have heard of.

LangGraph with a deep-agent framework
The orchestrator, 32 domain agents, subagents, and the middleware stack around them.Graph-level checkpointing and middleware give a single place to attach guards, budgets and compaction so every agent inherits them.
Vertex AI model registry
One library of runnable models behind three role tiers, overridable per tier and per agent.Makes model choice an operational lever. Adding a model is one row; retuning routing is a configuration change rather than a release.
SAP HANA
The read-only system of record, plus the conversation audit log.Access is guarded at the engine boundary and scoped by a role policy, with runtime host failover so a dead host does not need a redeploy.
A sandboxed JavaScript interpreter
Calculation over retrieved rows, enabled per domain by manifest policy.Arithmetic is something models do unreliably and sandboxes do exactly. Access, budget and trace regression tests keep the sandbox honest.
Cloud Run and Cloud Build
Deployment of the platform and its three surfaces.Instance lifecycle drives the design: shared engine state, runtime failover, and guards that bound a turn rather than a process.

6 more sections are written and hidden: constraints, evaluation, safety, leadership, deeper, stack.