diff --git a/.changeset/fix-sdk-stack-aao-and-tone.md b/.changeset/fix-sdk-stack-aao-and-tone.md new file mode 100644 index 0000000000..26ee740c97 --- /dev/null +++ b/.changeset/fix-sdk-stack-aao-and-tone.md @@ -0,0 +1,14 @@ +--- +--- + +docs(building): fix AAO hallucination + soften framing on sdk-stack page + +Two fixes to `docs/building/sdk-stack.mdx`: + +1. **AAO expansion fix.** The L2 bullet expanded AAO as "AdCP Authorization Object" linking to a non-existent `/docs/aao` page. AAO is AgenticAdvertising.org. Rewrote the bullet to describe what the SDK's AAO bridge actually resolves (member org, AAO Verified badges, registry visibility) with links to the registry and AAO Verified pages. + +2. **Reframed the intro and the "early implementers" section.** The opening previously called out "two audiences arriving at the same wrong conclusion" and the later section was titled "What early implementers underestimate" — both read as telling the reader they're wrong before laying out the data. Reframed around the actual choice — *where do you want to spend your engineering time?* — so the cost decompositions later in the page do the persuasion. Also softened the order-of-magnitude line and the TL;DR closer. + +3. **Named Python + TypeScript as first-class languages and added a contribution CTA.** Above the SDK coverage snapshot, called out that Python and TypeScript are committed to full L0–L4 coverage (TypeScript GA today, Python in flight on 4.x), Go is moving in the same direction, and community-maintained ports for other languages are welcome — with links to the Builders Working Group page and the AgenticAds Slack invite. + +4. **Threaded server/client asymmetry through the layer model.** The L0–L4 model previously read as if it described an agent only. Added an intro paragraph naming both sides, *Client side* notes at L0–L4, and a new "Server vs client at each layer" comparison table after L4 showing the cost asymmetry (a from-scratch caller is weeks-to-month at L0–L3; a from-scratch agent is the 3–4 person-month build documented later). Also flagged that the SDK coverage checklist describes the server surface and named the parallel client-side primitives an SDK should ship. diff --git a/docs/building/sdk-stack.mdx b/docs/building/sdk-stack.mdx index 4880f31ee6..ca1f35c469 100644 --- a/docs/building/sdk-stack.mdx +++ b/docs/building/sdk-stack.mdx @@ -9,15 +9,25 @@ description: "Layered reference for AdCP implementers. The five layers (L0 wire, **AdCP is the transaction and control plane** — planning, deal creation, creative submission, reporting. Impression-time decisioning happens in adjacent protocols ([TMP](/docs/trusted-match), RTB, VAST). AdCP latency budgets are seconds, often async-by-design — not the millisecond budgets you'd expect from a serve-time protocol. If you came here looking for a serve-time auction surface, you want [TMP](/docs/trusted-match). -Two audiences keep arriving at the same wrong conclusion: +The first question when you sit down to build an AdCP agent is **where you want to spend your engineering time**. By the time a buyer's `create_media_buy` reaches your business logic, it has crossed five distinct layers — wire format, signing, auth, protocol semantics, and finally what you actually want to build. The lower you start, the more of the stack you own. -1. **Early implementers** who built before the SDKs were mature, looked at what the SDK shipped at the time, and decided to roll their own. Most of what the SDKs provide today didn't exist when they made that call — so their mental model of "what an SDK does" is frozen at AdCP 2.5 and a few hundred lines of transport glue. -2. **New implementers** who say *"I'll build my own AdCP agent from scratch — I don't need an SDK."* AdCP looks like a thin protocol from the outside; from the inside, by the time a buyer's `create_media_buy` reaches business logic, it has crossed five distinct layers of protocol concern, each non-trivial and each governed by a published spec contract. +This page lays out those layers, what an SDK provides at each one, and what's left for you to write either way. Use it to pick the entry point that fits your team — whether that's letting an SDK absorb the protocol surface so you can focus on the L4 logic that differentiates your agent, or going lower because you have a specific reason to. The cost decompositions further down ([per-component L3 breakdown](#why-sdks-matter-more-in-adcp-than-in-eg-http), [version-adaptation](#version-adaptation)) are there to make either choice deliberate. -This page names the layers, says what each one contains, says what an SDK at each layer should provide, says how the SDK absorbs **version drift** (spec version, SDK version, and per-peer version) so adopters don't, and is honest about what *"from scratch"* signs you up for. Audience: AdCP implementers in any language — whether you're building an agent, authoring an SDK, or evaluating one. +Two notes on framing before the layers: + +- **The protocol surface has grown.** AdCP 3.0 added mandatory idempotency, published lifecycle state machines, the [conformance test surface](/docs/building/implementation/comply-test-controller), RFC 9421 signatures as a baseline, and the recovery-classified error catalog. If you last evaluated SDKs against an earlier version, the line between "what the SDK does" and "what I'd write myself" has moved. +- **AdCP looks like a thin protocol from the outside.** From the inside it has more L3 (state machines, idempotency, async-task contract, error semantics, conformance) than implementers tend to expect on a first read. The decompositions on this page exist so the L3 estimate is visible up front. + +Audience: AdCP implementers in any language — whether you're building an agent, authoring an SDK, or evaluating one. ## The five layers +The same five layers exist on both sides of an AdCP conversation — **agent (server)** and **caller (client)**. The work is asymmetric, though: an agent **enforces** the protocol (state machines, idempotency, error semantics, conformance surface, webhook emission), while a caller **consumes** it (reads state, supplies idempotency keys, handles errors, receives webhooks). L0 (wire) and L1 (signing) are mostly symmetric; L2 (auth) and especially L3 (protocol semantics) are where the surface diverges. L4 exists on both sides, but it's a different shape — the agent's L4 is its inventory and decisioning, the caller's L4 is its planning and buying logic. + +When this page describes a layer in agent-shaped terms, look for the *Client side* note at the end — it names the (typically smaller) caller-side surface. Most of the per-page cost commentary, the L3 person-month estimates, and the conformance discussion all describe the server side; building a caller is meaningfully lighter at L2–L3 because most of the work is consuming the protocol, not enforcing it. + +**Caller-only?** Skim the *Client side* notes on each layer below, then jump to [Server vs client at each layer](#server-vs-client-at-each-layer) for the cost comparison. + ```mermaid %%{init: {"flowchart": {"htmlLabels": true, "wrappingWidth": 9999}, "themeVariables": {"fontSize": "14px"}}}%% flowchart TB @@ -53,6 +63,8 @@ What's in it: If you only have L0, you have a parser. The buyer's `create_media_buy` is a typed object on your stack — and you have to do everything else yourself. +*Client side:* same primitives, mirror direction. The client serializes outbound requests against the same schemas and consumes responses through the same type-generation pipeline. L0 is essentially symmetric. + ### L1 — Identity & signing What it does: cryptographically verifies that the request came from who the headers claim it did, and that the body wasn't modified in transit. See [Security model](/docs/building/understanding/security-model) and the [implementation profile](/docs/building/implementation/security). @@ -67,6 +79,8 @@ What's in it: If you have L0+L1, you know who's calling you. You still don't know *what* they're allowed to do. +*Client side:* signs outbound requests with its own key; verifies webhook callbacks from the agent. Same RFC 9421 + replay-window + key-rotation primitives, just one inbound path (webhooks) instead of every request. + ### L2 — Auth & registry What it does: turns a verified identity into a scoped principal — which buyer, which brand, which advertiser account, which sandbox-vs-live tier. See [Accounts](/docs/accounts/overview) and [Calling an agent](/docs/protocol/calling-an-agent). @@ -75,13 +89,15 @@ What's in it: - Agent registry lookup (resolving agent metadata from a published [agent card](/docs/protocol/calling-an-agent)). - Brand resolution: mapping the requesting agent to a buyer brand / advertiser identity via [Brand Protocol](/docs/brand-protocol). -- AAO ([AdCP Authorization Object](/docs/aao)) bridge for delegated authority chains. +- AAO ([AgenticAdvertising.org](https://agenticadvertising.org)) bridge: resolving an agent's member org, AAO Verified badges, and registry visibility — see [Registering an agent](/docs/registry/registering-an-agent) and [AAO Verified](/docs/building/aao-verified). - Multi-tenant account resolution: the same wire request maps to different accounts depending on the principal. - Sandbox-vs-live account flagging — see [Sandbox](/docs/media-buy/advanced-topics/sandbox). - Permission scoping: which AdCP tools this principal is allowed to call. If you have L0+L1+L2, you have a verified, scoped principal asking to do something. You still don't know if the *something* is legal in the current state. +*Client side:* a small subset. The client publishes its own identity (agent card, brand domain), looks up the agent it's calling via the registry, and presents its credentials. There's no multi-tenant routing, no principal scoping, no sandbox/live boundary to enforce — the client *is* the principal, and chooses which agent to talk to. + ### L3 — Protocol semantics What it does: enforces what AdCP *means*. The wire shape is well-formed (L0); the caller is authentic (L1) and authorized (L2); now: is the request legal given the current state of the world? @@ -99,6 +115,8 @@ What's in it: If you have L0+L1+L2+L3, you have a complete AdCP protocol implementation. You still haven't done any business logic. +*Client side:* the consumer-side mirror, which is much smaller. The client *reads* state machines (handles each terminal status correctly) rather than enforcing transitions. It *supplies* `idempotency_key` on retries rather than maintaining the cache. It *classifies* error codes by recovery semantics (`transient` → retry, `correctable` → fix and resubmit, `terminal` → don't retry) rather than choosing the right one to emit. It *polls or receives* async-task results and webhook callbacks rather than emitting them. There's no `comply_test_controller` surface to expose, and no conformance bar to certify against on the consumer side. The L3 person-month estimate later on this page is server-side; client L3 is weeks of handler glue, not months. + ### L4 — Business logic This is what makes your agent yours. @@ -113,10 +131,28 @@ What's in it: This is the layer an AdCP SDK leaves to you, **and only this layer**. +*Client side:* L4 is also yours, just a different shape. The caller's L4 is media planning, budget allocation, target-audience selection, deal evaluation, reporting ingest — whatever your buy-side application does with the agents it calls. See [Calling an agent](/docs/protocol/calling-an-agent) for the spec-side reference. The asymmetry runs through the whole stack: agent L4 differentiates *inventory*, caller L4 differentiates *demand*. + +## Server vs client at each layer + +The same five layers; very different cost. Use this when sizing the work for a caller-only build vs. an agent build. + +| Layer | Agent (server) | Caller (client) | +|---|---|---| +| **L4** | Inventory, pricing, creative review, ad-server integration. What differentiates you as a seller. | Planning, budgeting, agent selection, reporting consumption. What differentiates you as a buyer. | +| **L3** | **Enforces** state machines, idempotency, error semantics, conformance test surface, webhook emission. ~3–4 person-months. | **Consumes** the same. Reads state, supplies idempotency keys, classifies errors, polls/receives async + webhooks. Weeks of handler glue. | +| **L2** | Multi-tenant principal resolution, sandbox/live boundary, brand resolution, permission scoping. | Publishes own identity; looks up the agent it's calling. Much smaller surface. | +| **L1** | Verifies inbound on every request; signs outbound webhooks. | Signs outbound on every request; verifies inbound webhooks. Same crypto, mirrored path. | +| **L0** | Receives + parses + validates against schemas. | Serializes + sends + validates against schemas. Symmetric. | + +A from-scratch caller is a weeks-long job across L0–L3 — handler glue, signing, registry lookup, response parsing — not the [3–4 person-month L3 build](#why-sdks-matter-more-in-adcp-than-in-eg-http) the agent side requires. The rest of this page concentrates on the agent side because that's where the cost lives, but the layer model and the SDK coverage matrix apply equally to a caller-only build. + ## What an SDK at each layer should provide Implementer-facing checklist. An SDK that claims coverage of layer L*n* should expose, at minimum, the primitives below. Adopters use this as a self-evaluation tool when picking an SDK; SDK authors use it as a build target. +The checklist describes **server-side coverage** — the agent surface is where the bulk of an SDK's value lives. **Client-side coverage** at each layer is a subset: typed request builders + response parsers (L0), outbound signing + webhook verification (L1), agent-card publication + registry lookup (L2), state-machine *handlers* + idempotency-key generation + error-recovery classification + async-result polling (L3). A full-stack SDK ships both. + ### L0 coverage - Generated language-native types from the published JSON schemas (one type per request/response pair, plus shared resource types). @@ -160,6 +196,8 @@ Within a given language, the full-stack SDK is the default starting point. The l ### Current SDK coverage +**Python and TypeScript are the first-class languages.** Both are committed to full L0–L4 coverage — TypeScript is GA across L0–L3 today; Python is finishing its 4.x cycle to the same bar. **Go** is moving in the same direction, with L0 and partial L1 in active development. **Other languages** are not on the official roadmap today, but we're open to community-maintained ports — if you want to help, see the [Builders Working Group](/docs/community/working-group) and the [Slack community](https://join.slack.com/t/agenticads/shared_invite/zt-3c5sxvdjk-x0rVmLB3OFHVUp~WutVWZg). + Snapshot of what each official SDK ships today. Refresh this table on SDK majors and on AdCP spec revs. *Last updated: 2026-05-03 — `@adcp/sdk` 6.7.0 GA on npm; `adcp` (Python) 4.x in flight; `adcp-go` in active development.* @@ -243,7 +281,7 @@ That's **~14–18 weeks**, depending on team familiarity with HTTP message-signa This is a single-engineer-to-mock-conformance estimate. **At publisher / large-platform scale, multiply by ~2× to ~3×** for SRE, security review, KMS / HSM integration with existing key infrastructure, load testing, and on-call burden — none of which is L3 spec work, all of which is real cost before the surface is production-grade. -Most teams that say *"I'll build from scratch"* count the wire shape (L0) and underestimate L3 by an order of magnitude. +"From scratch" reads cheap when L0 (the wire shape) is the only layer in view. L3 is where the actual scope hides — the table above is what we'd point a team at before they commit either way. ## Version adaptation @@ -271,17 +309,17 @@ The spec itself has already done one of these crossings. **2.5 → 3.0** added m The from-scratch path that worked for 2.5 doesn't scale to 3.0, and 3.0 isn't where the spec stops. SDKs exist because L3 grew faster than implementers could hand-roll, and the version-adaptation surface keeps growing each release. -## What early implementers underestimate +## Where the work actually lives -Rough order of pain, for adopters who built before the SDKs covered much: +Five places L3 cost concentrates, in rough order of magnitude. Useful as a self-check whether you're scoping a from-scratch build or re-evaluating a hand-rolled one: 1. **L3 is most of the work.** State machines, idempotency, error catalog, async tasks — ~3–4 person-months before any L4 differentiation. See the [decomposition](#why-sdks-matter-more-in-adcp-than-in-eg-http) for per-component weeks. -2. **Conformance is L3-driven.** Storyboards probe state transitions and error shapes (see [Conformance](/docs/building/conformance)). Without an SDK's transition validators you re-derive the spec from test failures. -3. **Versioning compounds.** Each spec rev that adds a tool, a lifecycle edge, or an error code is a new translation row your adapters carry. Bypassing the SDK means owning that matrix forever. -4. **RFC 9421 + key rotation is its own project.** Signing providers, KMS integration, replay windows — none of which moves the needle on your L4 differentiation. +2. **Conformance is L3-driven.** Storyboards probe state transitions and error shapes (see [Conformance](/docs/building/conformance)). Without transition validators, the spec gets re-derived from test failures. +3. **Versioning compounds.** Each spec rev that adds a tool, a lifecycle edge, or an error code is a new translation row the adapter layer carries. Owning the adapter layer means owning that matrix every release. +4. **RFC 9421 + key rotation is its own project.** Signing providers, KMS integration, replay windows — real engineering, none of it L4 differentiation. 5. **The mock-server is shared infrastructure.** SDKs wire mock-mode dispatch to it for free. Hand-rolled implementations either skip mock-mode (and lose spec-compliance certification) or rebuild it. -If you built early, the honest move is to re-evaluate the SDKs against this list — not against the version you remember. The [migration guide](/docs/building/migrate-from-hand-rolled) walks the swap-one-layer-at-a-time path: which layer to swap first, what conflict modes to watch for, and which intermediate states still pass conformance. +If you built before the SDKs covered much, this list is the input to a re-evaluation — not a verdict either way. The [migration guide](/docs/building/migrate-from-hand-rolled) walks the swap-one-layer-at-a-time path for teams who decide a partial swap is worth it: which layer to swap first, conflict modes to watch for, which intermediate states still pass conformance. ## What this means for compliance @@ -299,4 +337,4 @@ The reference mock-server is the **spec-compliance oracle** — a black-box AdCP - A full-stack AdCP SDK lifts you to L4. You write business logic; the SDK handles the protocol. Different language SDKs cover different subsets of L0–L3; pick one that matches how much of the protocol you want to inherit — see the [coverage matrix](#current-sdk-coverage). - **Version adaptation is an SDK feature, not an adopter project.** Per-call spec-version adapters, co-existence imports across SDK majors, and on-wire `adcp_major_version` negotiation let you talk to peers on any supported version without forking your handlers. Hand-rolled agents inherit the entire translation matrix forever. - Compliance comes in two flavors: **spec compliance** (mock-mode, protocol-only, L3 reference test) and **live compliance** (sandbox-mode, full-stack, L0–L4 end-to-end; planned). -- If you built before the SDKs were mature, the value of staying hand-rolled is now measured against today's SDKs, not the ones you evaluated in 2.5. +- If you last evaluated SDKs before 3.0, the comparison has moved — most of L3 (state machines, idempotency, conformance surface, expanded error catalog) shipped with 3.0. Re-evaluate against today's coverage, not the one you remember. diff --git a/specs/building-ia-by-layer.md b/specs/building-ia-by-layer.md new file mode 100644 index 0000000000..aa574537ca --- /dev/null +++ b/specs/building-ia-by-layer.md @@ -0,0 +1,193 @@ +# Reorganize `/docs/building` by layer + +A proposed information architecture for the `/docs/building` section, organized by the L0–L4 stack model introduced on `/docs/building/sdk-stack`. Goal: turn 13 flat top-level pages plus three half-overlapping subgroups into a single nav whose shape *is* the decision the reader is making. + +## Problem + +Today `/docs/building` has 13 top-level pages plus `understanding/`, `integration/`, and `implementation/` subgroups. Five of those top-level pages overlap on the same audience — `where-to-start`, `sdk-stack`, `schemas-and-sdks`, `build-an-agent`, `migrate-from-hand-rolled` all answer some version of "how do I start." The result: + +- A new reader can't tell which page is the entry point. +- The depth signal (use SDK vs. go lower) is buried — every reader sees every page regardless of how deep they need to go. +- Cross-cutting pages (`version-adaptation`, `schemas-and-sdks`) sit at the same nav level as scoped pages (`grading`, `aao-verified`), which flattens the hierarchy and hides what's foundational. +- Verification surfaces (`conformance`, `aao-verified`, `grading`, `validate-your-agent`, `get-test-ready`, `compliance-catalog`) are scattered across the top level. + +## Goal + +The nav should answer the reader's first question — *how deep do I need to go?* — with a single decision point, and stop being relevant once they've stopped descending. A reader who picks an SDK and writes L4 should not have to walk past L1 RFC 9421 pages to get to "operating an agent." + +## Proposed top-level shape + +The L0–L4 spine is the same for both sides of an AdCP conversation — **agent (server)** and **caller (client)** — but the work is asymmetric (server enforces, client consumes). Each layer in the build-by-layer group surfaces both perspectives, with caller-side typically a subset. The reader picks a side at L4 and the lower layers stay parallel. + +``` +Building +├── Overview ← decision page; replaces today's index + where-to-start +├── Concepts (orthogonal — kept separate) +│ ├── Why AdCP +│ ├── How agents communicate +│ ├── AdCP vs OpenRTB +│ ├── Protocol comparison +│ ├── Security model +│ └── Industry landscape +├── Build by layer ← the new spine +│ ├── L4 — Business logic (start here) +│ │ ├── Choose your SDK +│ │ ├── Build an agent (server side, skill-file path) +│ │ ├── Build a caller (client side) +│ │ └── Migrate from hand-rolled +│ ├── L3 — Protocol semantics (going lower) +│ │ ├── Lifecycle state machines ← server enforces, client handles +│ │ ├── Idempotency ← server caches, client generates keys +│ │ ├── Async tasks & webhooks ← server emits, client receives +│ │ ├── Error handling ← server emits, client classifies +│ │ ├── comply_test_controller (server-only; conformance surface) +│ │ └── Response envelope ← server populates, client parses +│ ├── L2 — Auth & registry +│ │ ├── Account state (server-side multi-tenancy) +│ │ ├── Agent identity & registry lookup ← both sides; client publishes + looks up +│ │ ├── Authentication ← both sides +│ │ ├── Brand resolution & AAO bridge ← both sides +│ │ └── Accounts and agents (server-side scoping) +│ ├── L1 — Identity & signing +│ │ ├── RFC 9421 message signatures ← symmetric; mirrored direction +│ │ ├── Webhook verifier tuning ← server emits, client verifies +│ │ └── Key rotation & KMS ← both sides +│ └── L0 — Wire & transport ← symmetric on both sides +│ ├── Schemas +│ ├── MCP integration +│ ├── A2A integration +│ └── A2A response extraction / MCP response extraction +├── Cross-cutting (spans all layers) +│ ├── SDK stack reference ← the meta map +│ ├── Version adaptation +│ └── Known ambiguities +├── Verification & trust (primarily server-side) +│ ├── Conformance +│ ├── Compliance catalog +│ ├── Validate your agent +│ ├── Grading +│ ├── Get test ready +│ └── AAO Verified +└── Operating (both sides; weighted server) + ├── Operating an agent + ├── Storyboard troubleshooting + ├── Transport errors + ├── Orchestrator design + └── Seller integration +``` + +### Server vs client through the nav + +Three ways to handle the asymmetry without doubling the page count: + +1. **Per-page side-band callouts** (recommended). Each layer-page leads with the server view (which is where the bulk of the work is) and ends with a "Client side" callout that names the (lighter) caller surface. Same pattern the rewritten `sdk-stack` page uses. +2. **Tabs within a page.** Each L0–L3 page exposes Server / Client tabs. Cleaner separation, but tabs hide content from search and from the "scroll the page to learn the layer" reader. +3. **Side-specific subpages.** Every layer-page splits into `…/server` + `…/client`. Cleanest separation, but doubles nav weight and most pages would have a tiny client half. + +Recommend **option 1**: it matches the asymmetry (server-heavy with a smaller mirrored client surface) without doubling pages. The two L4 entries (`Build an agent` and `Build a caller`) are the explicit fork; below L4 the side-band approach handles the divergence. + +## Per-page disposition + +Every existing page in `docs/building/`: + +| Current path | New home | Notes | +|---|---|---| +| `building/index` | `building/index` (rewritten) | Becomes a single decision page that absorbs `where-to-start` + the section-overview content. Delete the three Card-Group hand-off into Understanding / Foundations / Implementation. | +| `building/where-to-start` | merged into `building/index` | Same audience, same content shape — they fight each other. | +| `building/sdk-stack` | `building/cross-cutting/sdk-stack` | Stays as the meta-map; the layered nav is its embodiment. | +| `building/schemas-and-sdks` | split: SDK list → `building/by-layer/L4/choose-your-sdk`; schemas content → `building/by-layer/L0/schemas` | Two concerns under one title today. | +| `building/build-an-agent` | `building/by-layer/L4/build-an-agent` | The L4 server-side entry point. | +| *(new page)* | `building/by-layer/L4/build-a-caller` | The L4 client-side entry point. Does not exist today; pulls existing caller content from `/docs/protocol/calling-an-agent` into a build-shaped page. | +| `building/migrate-from-hand-rolled` | `building/by-layer/L4/migrate-from-hand-rolled` | Logically L4 (deciding which layer to swap), even though the content discusses lower layers. | +| `building/version-adaptation` | `building/cross-cutting/version-adaptation` | Cuts across L0–L3. | +| `building/get-test-ready` | `building/verification/get-test-ready` | | +| `building/validate-your-agent` | `building/verification/validate-your-agent` | | +| `building/grading` | `building/verification/grading` | | +| `building/conformance` | `building/verification/conformance` | | +| `building/compliance-catalog` | `building/verification/compliance-catalog` | | +| `building/aao-verified` | `building/verification/aao-verified` | The trust mark; sits at the end of the verification group. | +| `building/operating-an-agent` | `building/operating/operating-an-agent` | | +| `building/understanding/*` (6 pages) | `building/concepts/*` | Rename group; content unchanged. "Concepts" reads better than "Understanding AdCP" as a sibling to "Build by layer." | +| `building/understanding/index` | `building/concepts/index` | Rename only; rewrite the group landing copy to match the new "Concepts" framing. | +| `building/integration/index` | *delete* | Replaced by per-layer landings (L0, L1, L2). The current Foundations group landing has no equivalent under "Build by layer." Redirect to `building/by-layer/L0`. | +| `building/implementation/index` | *delete* | Same — replaced by per-layer landings (L1, L3) plus `building/operating/`. Redirect to `building/by-layer/L3` (most-cited destination for current Implementation-group inbound links). | +| `building/integration/mcp-guide` | `building/by-layer/L0/mcp-guide` | | +| `building/integration/a2a-guide` | `building/by-layer/L0/a2a-guide` | | +| `building/integration/a2a-response-format` | `building/by-layer/L0/a2a-response-format` | | +| `building/integration/context-sessions` | `building/by-layer/L2/context-sessions` | Sessions are an L2 concern (principal scoping over time). | +| `building/integration/authentication` | `building/by-layer/L2/authentication` | | +| `building/integration/account-state` | `building/by-layer/L2/account-state` | | +| `building/integration/accounts-and-agents` | `building/by-layer/L2/accounts-and-agents` | | +| `building/implementation/task-lifecycle` | `building/by-layer/L3/task-lifecycle` | | +| `building/implementation/async-operations` | `building/by-layer/L3/async-operations` | | +| `building/implementation/webhooks` | `building/by-layer/L3/webhooks` | | +| `building/implementation/error-handling` | `building/by-layer/L3/error-handling` | | +| `building/implementation/comply-test-controller` | `building/by-layer/L3/comply-test-controller` | | +| `building/implementation/orchestrator-design` | `building/operating/orchestrator-design` | Runtime design pattern. | +| `building/implementation/security` | `building/by-layer/L1/security` | RFC 9421 implementation profile. | +| `building/implementation/webhook-verifier-tuning` | `building/by-layer/L1/webhook-verifier-tuning` | Signature verification tuning. | +| `building/implementation/transport-errors` | `building/operating/transport-errors` | Operational concern. | +| `building/implementation/mcp-response-extraction` | `building/by-layer/L0/mcp-response-extraction` | | +| `building/implementation/a2a-response-extraction` | `building/by-layer/L0/a2a-response-extraction` | | +| `building/implementation/seller-integration` | `building/operating/seller-integration` | | +| `building/implementation/storyboard-troubleshooting` | `building/operating/storyboard-troubleshooting` | | +| `building/implementation/known-ambiguities` | `building/cross-cutting/known-ambiguities` | Cuts across the spec. | + +## Cross-cutting page handling + +Three pages don't fit cleanly under one layer and need a `cross-cutting/` group at peer level to "Build by layer": + +- **SDK stack reference** — by definition spans all layers; it *is* the map. +- **Version adaptation** — touches L0 (wire), L3 (error), and the SDK majors story. +- **Known ambiguities** — spec-level edge cases that surface across layers. + +A fourth case to flag — **schemas-and-sdks** today bundles the SDK-coverage matrix (L4 picking question) with the schema-bundle reference (L0 wire concern). The spec proposes splitting it; the SDK list goes under L4 ("Choose your SDK"), the schema-bundle reference goes under L0. + +## Redirect map + +Mintlify supports redirects via `docs.json` `redirects[]`. Every moved page needs an entry. Skeleton: + +```json +{ + "redirects": [ + { "source": "/docs/building/where-to-start", "destination": "/docs/building" }, + { "source": "/docs/building/integration/mcp-guide", "destination": "/docs/building/by-layer/L0/mcp-guide" }, + { "source": "/docs/building/implementation/task-lifecycle", "destination": "/docs/building/by-layer/L3/task-lifecycle" } + // … one entry per moved page; ~30 total + ] +} +``` + +Inbound link audit also needed: `rg "docs/building/" docs/ server/ -l` to catch internal cross-links the move would break. Most cross-links are anchor-targets within `sdk-stack` and the storyboard-error pages; both stay where they are or move predictably. + +## Phasing + +Two options: + +1. **Single PR.** All page moves + redirects + nav rewrite + the new `building/index` decision page in one shot. Simpler review (the mental model is whole), riskier merge (every internal link in the docs needs to land in the same commit). +2. **Three PRs.** + - PR1 — Add the new `building/index` decision page; leave existing pages in place. Low risk; tests the new entry point. + - PR2 — Move pages into `by-layer/`, `concepts/`, `cross-cutting/`, `verification/`, `operating/` subdirs; add all redirects. The big one. + - PR3 — Split `schemas-and-sdks` into `L0/schemas` + `L4/choose-your-sdk`; rewrite the merged content. + +Recommend **option 2** — PR1 and PR3 are each independently shippable, and PR2 is a mechanical move that's easier to review on its own. + +## Decisions + +Locked in 2026-05-03 in conversation with Brian: + +1. **Concepts (renamed from "Understanding AdCP").** Group-title strings don't drive search rankings; page titles do, and those don't change. Low-cost, better hierarchy signal. +2. **Hosted implementations table stays on `sdk-stack`.** It sits next to the SDK coverage matrix because it answers the same question with a different shape ("library vs deployable agent"). Moving to `Operating` would split a unified comparison. +3. **Sidebar depth: three levels is fine.** Mintlify renders nested groups well. Default-expand state: L4 expanded (the recommended path); L0/L1/L2/L3 collapsed (so the sidebar isn't a wall of links). Readers actively descending click each layer open deliberately. +4. **Caller-side asymmetry: per-page side-band callouts.** Matches the real asymmetry (server-heavy with a lighter mirrored client surface), keeps both perspectives indexable on one page, avoids tab content disappearing from search. Explicit L4 fork (`Build an agent` vs `Build a caller`) gives caller-only readers a top-of-page entry point. +5. **`/docs/protocol/calling-an-agent` overlap: fork.** `/protocol/` keeps the spec-level reference (what `get_adcp_capabilities` returns, agent-card fields). `/building/by-layer/L4/build-a-caller` becomes the implementation guide (install SDK, write a calling app, handle errors, ingest reporting). Different audiences, different shapes; the build-side page is what's missing. + +## Deferred + +1. **Verification placement.** Whether the verification group lives under `/building` (today), gets promoted to a top-level section, or splits (trust narrative top-level + build-loop tools under `/building`) — **deferred until the AAO Verified L3/L4 reframing lands.** The current `(Spec)` / `(Live)` qualifier framing is being reconsidered as L3 Verified (protocol-correct, storyboard-issued) vs L4 Verified (real-inventory-behaving-correctly, observation-issued), which would map cleanly onto the L0–L4 spine of the rest of the build section. Tracked under the [Trust, Identity, and Governance in AdCP master epic](https://github.com/adcontextprotocol/adcp/issues/3925) and the [canonical test campaigns RFC](https://github.com/adcontextprotocol/adcp/issues/3046). Revisit verification placement once that reframing is decided — the mapping may make the "promote vs split" question answer itself. + +## Non-goals + +- Rewriting page content. This spec is about IA, not copy. A few merges (where-to-start → index, schemas-and-sdks split) require rewriting; everything else is pure relocation + redirects. +- Touching `/docs/protocol/`, `/docs/registry/`, or other top-level sections. Caller-side material may want a layered home eventually but is out of scope here. +- Changing the L0–L4 model itself. The spec on `sdk-stack` is the source of truth; this IA spec just embodies it in nav.