TECH STACK · Playbook — INTEGRATIONS: How the Stack Connects to Everything Else

Phase-3 draft, 2026-07-12. Engineer-nod bar. ⚑ unverified marks hard claims to confirm before publish; marks sign-up-able services for link treatment. Stage only.
A model that can't touch anything is a very expensive autocomplete. The intelligence in the stack — the models, the orchestration, the retrieval — only turns into work when it's wired to the systems where work actually lives: your email, your CRM, your codebase, your database, your customer's browser. Integration is where most AI projects succeed or die, and it's the least glamorous part of the stack, which is exactly why it's worth understanding properly.
This playbook covers the five ways the AI stack connects to everything else: the protocol that became the standard (MCP), the raw API patterns underneath everything, the no-code automation layer, the enterprise connectors big vendors sell, and the decisions you face when you embed AI inside your own product. Blunt version first, detail after.
1. MCP — the integration standard
The problem it solved
Before late 2024, connecting AI to tools was an N×M problem. Every AI application (Claude, ChatGPT, Cursor, your internal agent) needed a custom connector for every data source (GitHub, Slack, Postgres, Google Drive). Ten applications times a hundred tools is a thousand bespoke integrations, each one maintained by whoever felt like it, each one breaking differently. Function calling — the model emitting a structured "call this function" request — solved half the problem: the model could ask for a tool. Nobody had standardized how the tool got found, described, and executed.
The Model Context Protocol, released by Anthropic in November 2024 ⚑ unverified, is the USB-C answer: one protocol between AI applications and tool servers. Build your GitHub connector once as an MCP server, and every MCP-capable client — Claude, ChatGPT, Cursor, VS Code, your own agent — can use it. N×M becomes N+M. That's the entire pitch, and it was enough.
The architecture
MCP is a client-server protocol over JSON-RPC 2.0. Three roles:
- Host — the AI application the user is actually in: Claude Desktop, Cursor, an IDE, your agent harness.
The host owns the model, the conversation, and the security decisions.
- Client — the connector object inside the host. One client per server connection; it handles the
protocol session, capability negotiation, and message routing.
- Server — the thing that exposes capabilities. Can be a local process talking over stdio (great
for filesystem and dev tools) or a remote service over Streamable HTTP (the transport that replaced the original HTTP+SSE design in the March 2025 spec revision ⚑ unverified). Remote servers authenticate with OAuth 2.1.
A server exposes three kinds of primitives, and the distinction matters:
- Tools — functions the model decides to call ("create_issue", "query_database"). Each has a name, a
description, and a JSON Schema for inputs. This is the workhorse primitive; for most servers it's the only one that gets used.
- Resources — data the application attaches to context (a file, a table schema, a log stream).
Read-oriented, addressed by URI.
- Prompts — templates the user invokes explicitly (slash commands, canned workflows).
The client and server negotiate capabilities at session start, the client lists what's available, and the model calls tools through the host — which means the host can gate every call behind approval, logging, or policy. That mediation point is not decoration; it's the only place security can actually live (see below).
Who adopted it — and why it won
The adoption curve is the story. OpenAI — the competitor with the most to gain from a rival standard — adopted MCP across its Agents SDK and ChatGPT in March 2025 ⚑ unverified. Google DeepMind confirmed Gemini support in April 2025 ⚑ unverified. Microsoft built MCP support into Windows 11 at Build 2025 and wired it through Copilot Studio ⚑ unverified. Server downloads went from roughly 100K in November 2024 to over 8 million by April 2025 ⚑ unverified. An official MCP Registry launched in September 2025 as a public index of servers ⚑ unverified, and in December 2025 Anthropic donated the protocol to the Agentic AI Foundation under the Linux Foundation, with OpenAI and Block as co-founders and AWS, Google, Microsoft, Cloudflare, GitHub, and Bloomberg as supporting members ⚑ unverified. At donation time there were over 10,000 active public MCP servers ⚑ unverified.
Why did it win, when protocol land-grabs usually fragment? Three reasons, in order of weight. It was open from day one — Apache-licensed spec, SDKs in every major language, no license fee, no gatekeeper — so adopting it cost competitors nothing but pride. It was boring in the right way — JSON-RPC, JSON Schema, OAuth; every piece already understood by every backend engineer. And it shipped with clients people already used — Claude Desktop and Cursor gave server authors an audience on day one, which gave hosts a server ecosystem, which gave the next host a reason to support it. Classic two-sided flywheel. By the time anyone might have proposed an alternative, the network effect had closed the question.
Building your first MCP server
Here is the honest size of the task: a useful MCP server is under a hundred lines. The Python SDK's FastMCP wrapper turns typed functions into tools — the docstring becomes the tool description the model reads, the type hints become the JSON Schema:
# server.py — pip install "mcp[cli]"
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("orders")
@mcp.tool()
def lookup_order(order_id: str) -> str:
"""Look up an order's status and shipping info by order ID."""
row = db.get_order(order_id) # your existing code
return f"{row.status}, ships {row.ship_date}, carrier {row.carrier}"
@mcp.tool()
def refund_order(order_id: str, reason: str) -> str:
"""Issue a refund for an order. Destructive — requires confirmation."""
return payments.refund(order_id, reason)
if __name__ == "__main__":
mcp.run() # stdio transport by default
Register it with a client (in Claude Desktop, a five-line entry in the config file pointing at python server.py), and the model can now look up and refund orders in plain conversation. The three things that separate a demo server from a good one: write tool descriptions for the model, not for humans — the description is a prompt, and vague descriptions produce wrong calls; return errors as useful text, because the model reads the error and self-corrects; and keep tools coarse — one search_orders(query) beats twelve micro-endpoints, because every tool definition costs context tokens and decision quality degrades as the tool list grows.
For remote deployment, swap stdio for Streamable HTTP, put OAuth in front, and you have a server any MCP-capable client on the internet can connect to.
Security — the part everyone skips
MCP's security story is real and unflattering, and you should hear it before wiring an agent to anything that matters. The core issue: the model reads tool descriptions as instructions. A malicious or compromised server can embed directives in its tool metadata — "tool poisoning," a form of indirect prompt injection — and the model will follow them with whatever authority you gave it. This is not theoretical: CVE-2025-54136 covered a tool-poisoning vector in a major MCP client ⚑ unverified, and in 2025 researchers demonstrated a WhatsApp MCP integration that could be manipulated into exfiltrating message history ⚑ unverified. The general failure shape is what security researcher Simon Willison calls the lethal trifecta: an agent with (1) access to private data, (2) exposure to untrusted content, and (3) a channel to send data out. Any MCP setup with all three is exploitable by design, no bug required.
Practical hygiene: treat every third-party server as untrusted code, because it is. Pin server versions and hash tool descriptions so a "rug pull" (server silently changing its tools after you approved them) gets caught. Give servers least-privilege credentials — a read-only database user, a scoped API token. Require human confirmation on destructive tools. In enterprises, put an MCP gateway in front — an allowlisted proxy that logs every call — rather than letting every desktop connect to arbitrary servers. None of this is exotic; it's the same posture you'd take with any plugin system that executes with your credentials. The difference is that here the "code" includes English sentences, and the interpreter is a model that wants to be helpful.
The ecosystem
Discovery runs through the official MCP Registry (an open index with API access, so clients can search it programmatically) plus vendor directories — Anthropic's connector directory, community lists, package registries. The practical picture in mid-2026: reference servers exist for essentially every mainstream system — GitHub, Slack, Postgres, Stripe, Notion, Google Drive, browsers, filesystems — and the major SaaS vendors now ship first-party remote servers rather than leaving it to community forks. Quality varies exactly the way npm quality varies. The registry tells you a server exists; it does not tell you the server is safe or good. Read the tool list before you connect it. It's a five-minute audit that most people skip.
2. API integration patterns
MCP standardizes agent-to-tool. Underneath and beside it sits the older, larger question: how your code talks to the model providers themselves. Four decisions cover most of it.
Direct API vs SDK vs framework
Every provider exposes a REST API; every provider ships official SDKs; and above both sits the framework layer (LangChain, LlamaIndex, Vercel AI SDK, and friends). The right default is the official SDK: you get typed requests, automatic retries on 429/5xx, streaming helpers, and timeout handling for free, and you're insulated from wire-format drift. Drop to raw HTTP only when you're in a language without an official SDK or you're debugging what's actually on the wire. Reach for a framework only when you're genuinely using what it abstracts — multi-step chains, swappable retrieval pipelines, provider portability you'll actually exercise. The failure mode is well documented by now: five layers of framework abstraction around what is, underneath, one HTTP call, and every provider-specific feature (caching controls, thinking budgets, beta headers) either unreachable or reachable through an escape hatch that defeats the abstraction. If your app makes three kinds of model calls, three thin functions beat a framework.
Streaming
Model responses take seconds to minutes. Non-streaming calls mean the user stares at nothing and your HTTP connection flirts with timeouts; streaming (server-sent events, in every provider's API) delivers tokens as they're generated. Rules of thumb: stream anything user-facing; stream anything with a large output cap, because idle connections get dropped by proxies long before the model finishes; and accumulate the streamed events into a complete response object at the end rather than string-concatenating deltas by hand — the SDKs all provide a final-message helper. Streaming complicates one thing: mid-stream errors arrive after you've already rendered half an answer, so your UI needs a "this response failed partway" state.
Structured output and function calling
The two mechanisms that make model output machine-usable. Function calling (tool use): you pass JSON Schema tool definitions, the model returns a structured call, you execute it and return the result — the primitive underneath every agent, and underneath MCP. Structured output: you constrain the response itself to a schema, so {"sentiment": "negative", "urgency": 4} comes back as parseable JSON every time instead of most times. Modern APIs enforce both server-side (strict schema modes), which killed a whole genre of regex-the-JSON-out-of-the-prose glue code. The rule: if code consumes the output, use a schema. Prose is for humans.
Errors, retries, rate limits
The model API is a remote dependency with its own weather. It will return 429s when you exceed rate limits, 529s when the provider is overloaded, and 500s occasionally, because everything does. The pattern is standard distributed-systems fare, and it's non-negotiable in production: retry 429 and 5xx with exponential backoff plus jitter; never retry 4xx validation errors; respect the retry-after header when the provider sends one. Official SDKs do this out of the box — one more reason to use them. Rate limits come in layers (requests per minute, input tokens per minute, output tokens per minute) and are reported in response headers; a serious integration reads those headers and sheds load before hitting the wall rather than after. Two more production habits: set explicit timeouts sized to your longest expected generation, and log the provider's request ID on every failure — it's the only handle support has when something goes wrong upstream.
The multi-provider question — when a router makes sense
Sooner or later someone asks: should we abstract over providers? The honest answer is usually later than you think. Provider APIs have converged enough that switching is a day of work, not a rewrite — and premature abstraction costs you provider-specific features (prompt caching semantics, thinking controls, context-window differences) that often matter more than portability.
The case where a router earns its keep: you genuinely need many models — routing cheap traffic to cheap models, comparing models in production, or absorbing provider outages with automatic fallback. OpenRouter is the reference implementation of this idea: one OpenAI-compatible API in front of 300+ models across every major provider ⚑ unverified, with pass-through token pricing — you pay what the provider charges, and OpenRouter takes its cut as a ~5.5% fee on credit purchases (about 5% if you bring your own provider keys) ⚑ unverified. Fallback routing and unified billing are the real product. The trade: an extra hop of latency, another party in your data path (check their logging and retention settings against your compliance needs), and a lowest-common-denominator API surface for provider-specific features. If you run one primary model in production, integrate directly and keep a tested fallback path. If you run ten, a router is cheaper than maintaining ten integrations yourself.
3. Workflow automation
Not every integration deserves code. A large share of real-world AI work is glue — when X happens, classify it, enrich it, put it somewhere — and the no-code automation platforms have spent 2025–2026 bolting AI steps into exactly that glue.
The three platforms
Zapier is the breadth play: 8,000+ connected apps ⚑ unverified, the largest catalog by far, plus "Zapier Agents" for goal-directed automations that decide their own steps within the apps you grant them. Pricing is per task — every step execution bills. Make (formerly Integromat) is the visual middle: ~3,000 apps ⚑ unverified, a genuinely good flow canvas with branching and iteration that Zapier handles awkwardly, per-operation pricing, and its own AI-assistant-builds-the-scenario feature. n8n is the engineer's option: source-available and self-hostable, which means your data can stay on your hardware — decisive for anything sensitive — with per-execution pricing (a 20-step workflow costs one execution, not twenty operations) and the deepest AI tooling of the three: n8n's 2.x line ships dozens of native AI and LangChain-derived nodes ⚑ unverified — agent nodes, memory, vector-store connectors, human-in-the-loop gates.
The pricing structures diverge more than the feature lists: high-volume, many-step workflows that are cheap on n8n's per-execution model get expensive fast on per-task and per-operation billing. Run the arithmetic on your actual volume before choosing; the monthly difference at 10K runs of a 10-step flow is roughly an order of magnitude ⚑ unverified.
When no-code beats custom code
The unfashionable truth: for internal glue workflows, the automation platform usually wins. The break-even logic: custom code wins when the workflow is your product, when latency matters, when volume makes per-task pricing absurd, or when the logic is genuinely complex. The platform wins when the workflow is internal plumbing, changes often, is owned by whoever operates it (an ops person can edit a Zap; they can't edit your Lambda), and touches many SaaS apps — because the platform has already built and maintains the 8,000 connectors you'd otherwise write. Authentication alone justifies it: every OAuth token refresh you don't implement is a pager alert you don't get.
Webhook patterns
Webhooks are the connective tissue in either direction — SaaS apps fire them at your automations, and your automations fire them at your services. Four habits separate reliable from flaky: verify signatures (every serious webhook is HMAC-signed; check it, or anyone who finds the URL can inject events); acknowledge fast, process async — return 200 immediately and queue the work, because an AI step takes seconds and webhook senders time out and retry, giving you duplicates; dedupe on event ID, because delivery is at-least-once everywhere; and expect disorder — events arrive out of sequence, so key decisions off fetched current state, not the event payload's snapshot.
A concrete example: inbound email → classify → route → draft reply
The canonical AI automation, buildable in an afternoon on any of the three platforms:
- Trigger — new email in the support inbox (native Gmail/Outlook trigger, or an inbound-parse webhook).
- Classify — one model call with structured output:
{"category": "billing|bug|sales|spam", "urgency": 1-5, "summary": "..."}. Temperature low, schema enforced. This is a cheap-model job — routing does not need frontier intelligence. - Route — branch on the JSON. Billing → ticket in the billing queue; bug → Linear issue with the summary; sales → CRM lead plus a Slack ping; spam → archive. Urgency ≥ 4 pages a human regardless.
- Draft — for categories with standard answers, a second model call drafts a reply — grounded in your help-doc content if you've wired retrieval in — and saves it as a draft in the agent's queue.
Note what the design does at step 4: it stops. The human sends the email. That single decision — AI drafts, human approves — is the difference between an automation that quietly saves hours a day and one that autonomously emails a customer something wrong. Full send-automation is earned later, category by category, with the misfire data to justify it. Start every workflow like this with the human gate in, and remove it deliberately, not by default.
4. The enterprise connectors
The big vendors' answer to integration is: don't integrate — buy the AI already inside the software you use. Sometimes that's the right answer. It helps to know what's actually being sold.
Chat platforms: Slack and Teams bots
The chat platform is the natural front door for workplace AI — it's where people already are, and a bot is an interface you don't have to build. Slack's app platform supports full AI-app patterns (streaming responses, threads as conversation state) and, post-acquisition, Salesforce ships its agents directly into Slack; Anthropic, OpenAI, and others ship first-party Slack apps ⚑ unverified. Teams is the same story with Microsoft's stack behind it — bots built on Copilot Studio or the Teams SDK. The integration pattern for your own bot is identical on both: events webhook in, model call in the middle, post back to the thread; thread history becomes conversation memory. One warning from the field: a chat bot is the easiest AI integration to demo and the hardest to make load-bearing, because chat strips away all the structure (forms, validation, state) that makes workflows reliable. Great for Q&A and retrieval; wrong shape for anything transactional.
Suite copilots: Microsoft 365 and Google Workspace
Microsoft 365 Copilot is the flagship: $30/user/month on top of an eligible M365 license ⚑ unverified, for AI inside Word, Excel, Outlook, Teams, grounded in your tenant's content via Microsoft Graph. Google Workspace folded Gemini into its business tiers — bundled into Workspace plans rather than a separate per-seat AI SKU ⚑ unverified. The honest evaluation for either: the per-seat math only works for seats that use it weekly, and adoption is wildly uneven across roles — pilot with usage telemetry before an org-wide rollout, because "we bought 5,000 seats and 400 people use it" is the modal enterprise outcome ⚑ unverified.
CRM: Salesforce Agentforce and HubSpot Breeze
CRM vendors moved fastest from "copilot" to "agent," and their pricing tells you what they think they're selling. Salesforce Agentforce prices per conversation — roughly $2 per conversation at list, with a flexible-credits model layered on ⚑ unverified — for agents that handle service cases and sales tasks on Salesforce data. HubSpot ships Breeze — copilot, prebuilt agents, and an intelligence/enrichment layer — on outcome-flavored credit pricing (on the order of $0.50 per resolved conversation for the service agent ⚑ unverified). The per-outcome pricing is the tell: the vendors are pricing agents against labor cost, not software cost. Evaluate them the same way — cost per resolved case versus your human cost per case, at your actual resolution quality, measured on your own tickets, not the vendor's demo set.
The realities: SSO and data governance
This is the section that decides enterprise deals, so it goes last and bluntly. Every AI feature above inherits your identity and permissions infrastructure — SSO via SAML/OIDC, provisioning via SCIM — and the first governance question is whether the AI respects per-user permissions at query time. Good copilots retrieve as you, so they can only surface what you could already open. That property has a famous failure mode: enterprise search-with-AI is an oversharing detector. Years of badly permissioned SharePoint sites and open shared drives were invisible when finding things was hard; a copilot that cheerfully retrieves them makes the latent permission mess an incident. Run a permissions audit before the rollout, not after the first surprised screenshot.
The rest of the checklist, compressed: where do prompts and outputs go (tenant boundary, data residency, retention, and — critically — is your data used for model training; every serious enterprise offering now answers "no" in writing, get it in writing anyway); do AI interactions land in the audit log and eDiscovery scope; do your DLP policies apply to what users paste into the assistant; and who inside the org can build agents that act with real credentials — because "citizen developers wiring agents to production systems" is this decade's shadow-IT, and the governance answer (an approval gate and an inventory) is boring and necessary.
5. Embedding AI in your product
Everything above is about consuming AI. The last mile is shipping it inside your own product — where the questions become architectural, and one of them is existential.
The build-vs-buy ladder
Four rungs, in ascending order of cost, control, and commitment:
Rung 1 — the API call. Prompt + provider API + your product's UI. An afternoon to ship. This is the right starting rung for almost everyone, and — this part gets forgotten — the right permanent rung for many features. Summarization, drafting, classification, extraction: a well-prompted frontier model over the API is the quality ceiling for these, not a compromise. Latency is the provider's latency; cost is per-token and scales linearly with usage; quality is the best available and improves every time the provider ships a model, for free.
Rung 2 — the RAG layer. The model plus retrieval over your data (see the Orchestration guide for the mechanics). This is the rung where your product starts doing something a competitor can't copy with a prompt: answering from your corpus, your customer's documents, your proprietary data. Adds real engineering surface — chunking, embeddings, a vector store, retrieval evals, data freshness — and a new latency term (retrieval before generation). Most durable AI products in 2026 live here. Cost note: RAG shifts spend from model tokens to engineering time; the tokens stay cheap, the pipeline maintenance doesn't.
Rung 3 — fine-tuning. Training a model (usually a small open-weights one, sometimes a provider's tunable tier) on your examples. Buys you: consistent style/format at lower per-call cost, lower latency from a smaller model, and behavior that's awkward to prompt for. Does not buy you knowledge — facts go in retrieval, behavior goes in fine-tuning; teams that tattoo this on the wall save themselves a quarter of wasted effort. Demands: thousands of good examples, eval infrastructure to know whether the tune helped, and re-tuning every time your base model or task drifts. The trap on this rung is doing it for status rather than economics — fine-tune when the per-call savings times call volume beats the training and maintenance cost, not because "we have our own model" sounds fundable.
Rung 4 — own weights. Self-hosting open models (or, at the far end, pretraining). Buys you: data that never leaves your infrastructure, no per-token marginal cost, no provider dependency, full control. Costs you: GPUs, an inference-serving stack, and the permanent gap between open weights and the frontier — which for some tasks doesn't matter and for others is the whole product. Justified by compliance (regulated data that cannot transit a third party), by scale (at sufficient volume, owned inference undercuts API pricing), or by product physics (on-prem or edge requirements). Not justified by vibes.
The ladder is not a maturity model. You do not graduate rung by rung; you match each feature to its rung and stop climbing when the economics stop improving. A serious product commonly runs three rungs at once — frontier API for hard reasoning, a fine-tuned small model for the high-volume cheap path, RAG under both.
The thin-wrapper trap — and what defensibility actually looks like
The trap, stated plainly: if your product is a prompt in front of someone else's model, your product is a feature — and the model vendor, or any weekend competitor, ships it next quarter. The 2023–2025 casualty list is long and rhymes: writing assistants absorbed by the model's own UI, PDF-chat apps flattened by file upload becoming a native feature, coding wrappers eaten by the coding agents themselves. Every one of them had users; none of them had a moat.
What actually defends an AI product, roughly in order of strength:
- Proprietary data with a flywheel. Not "we have data" — data the product generates in use that makes the product better, which no competitor can synthesize. Corrections, outcomes, domain-specific ground truth your usage produces.
- Workflow depth. The AI embedded where the work happens — inside the system of record, the approval chain, the compliance trail — so ripping it out means re-plumbing the process, not swapping an app. Integration surface, ironically, is a moat: the eighty connectors you built are eighty things a weekend clone doesn't have.
- Evaluation and reliability engineering. Anyone can hit the API; getting the last-mile failure rate from 8% to 0.8% on your task takes an eval suite, error taxonomy, and iteration nobody can shortcut. In domains where errors are expensive, this alone is the business.
- Distribution and trust. The enterprise agreements, the security review already passed, the seat in the customer's existing workflow. Boring, decisive.
Notice what's absent from the list: the model. Model quality is the one input every competitor buys from the same three vendors at the same price. Build assuming the model layer keeps commoditizing under you — because for two years straight, it has — and put your engineering where the commoditization can't reach.
The integration decision checklist
Ten questions, in the order they pay off:
- Does a connector already exist? MCP server, Zapier/Make/n8n node, native integration — check before writing code. The build-it reflex is the most expensive habit in this playbook.
- Agent-to-tool, or code-to-model? Agents calling tools → MCP. Your backend calling a model → direct SDK. Don't build an MCP server for a pipeline no agent will ever touch.
- Who reads the output? Code reads it → enforce a schema. Human reads it → prose and streaming.
- One model or many? One primary model → integrate directly, keep a tested fallback. Genuinely many → a router (OpenRouter) beats maintaining N integrations.
- Is this workflow the product, or plumbing? Product → code. Internal plumbing that ops should own → automation platform (Zapier / Make / n8n), with the volume math run first.
- Where's the human gate? Every workflow that acts externally — sends, posts, refunds, deletes — starts with draft-and-approve. Remove the gate per-category, with misfire data, never by default.
- What credentials does it hold, and what's the blast radius? Least privilege, scoped tokens, version pinning on third-party servers. Assume the lethal trifecta unless you've structurally ruled one leg out.
- Does it respect permissions at query time? For anything touching org data: retrieval as the user, permissions audit before rollout, AI interactions in the audit log.
- Which rung of the ladder, per feature? API call until proven otherwise; RAG when your data is the product; fine-tune on economics, not status; own weights on compliance or scale.
- What's the moat when the model layer commoditizes? If the honest answer is "the prompt," the integration is fine — the business plan isn't.
Verification sources for ⚑ unverified tags: MCP anniversary & spec history (blog.modelcontextprotocol.io, 2025-11-25 post); Linux Foundation / Agentic AI Foundation donation coverage (Dec 2025); OpenAI/Google/ Microsoft adoption reporting (Mar–May 2025, Wikipedia MCP entry aggregates); MCP Registry launch (Sept 2025); tool poisoning & CVE-2025-54136 (Truefoundry, Checkmarx, Simon Willison Apr 2025); OpenRouter pricing page & FAQ (fee schedule, model count); n8n 2.0 release notes (Jan 2026); platform comparisons (digitalapplied.com 2026 roundups); M365 Copilot pricing page; Salesforce Agentforce pricing page; HubSpot Breeze pricing page.
Some links on this page are affiliate links. If you sign up or buy through one, TheCatch.AI earns a commission at no extra cost to you. We list what we would use; the commission never decides the ranking, and nothing in Bubble Watch or Economics carries an affiliate link — analysis stays clean.