The distinguishing property of an internal platform is not that it is internal. It is that adoption is voluntary in practice even when it is mandatory on paper. A team told to use the platform can comply nominally, keep their own Terraform in a side repo, file exceptions, or route around the golden path through a legacy pipeline nobody has decommissioned. You have users who can leave, a competitor (raw cloud access, which is free, well-documented, and hires for itself), and no pricing signal telling you whether what you built is worth what it cost.

That is a product problem. Infrastructure teams are structurally bad at product problems, not because of ability but because of what the role has historically rewarded: correctness, reliability, and completeness. Product work rewards a different set — knowing which 20 percent to build, shipping something embarrassing to five users, and killing things.

Adoption is the metric, and most teams measure a proxy for it

The common platform dashboard shows services onboarded, pipelines running, environments provisioned. These count activity, not value, and they go up even when the platform is failing.

The measurements that tell you the truth:

MetricWhat it exposesHealthy
Share of eligible teams using the paved path for new servicesWhether you win by default>80% within two quarters of eligibility
Escape rate: teams that adopted and then built around youWhere the abstraction breaks<10%, and each one investigated
Time from empty repo to production trafficThe headline promiseHours, and trending down
Support tickets per adopting team per monthWhether self-service is realFalling as adoption grows
Fraction of platform work that is unplanned supportSustainability<30%

The escape rate is the one to watch. A team that onboarded and then quietly built a parallel deployment path has told you something specific and expensive: the platform blocked something they needed. That is your highest-value research input and it will never arrive as a feature request, because the team already solved their problem and has no incentive to relitigate it. You have to go find it.

The support-ticket ratio is the second. A self-service platform where every non-trivial operation requires a ticket to the platform team is a ticket queue with better branding. If that number is flat or rising as adoption grows, you have not built a product, you have built a job for yourselves — and the trajectory ends with the platform team as a permanent bottleneck. That specific failure and several relatives are catalogued in the anti-patterns piece.

Discovery when your users cannot say no

Normal product discovery relies on the fact that users vote with money and attention. Internal users are captive, which distorts every signal you get. They will be polite in interviews, agree that the roadmap sounds good, and then not adopt.

Four techniques that work better than asking.

Watch a real onboarding, silently. Sit with an engineer setting up a new service on your platform and say nothing for ninety minutes. Not a demo — an actual first attempt. You will learn more in that session than in a quarter of surveys. The specific things you find: which doc page they cannot locate, the point where they open Slack instead of continuing, the copy-paste they do not understand, the moment they say "I'll just do it the old way for now."

Read the shadow infrastructure. Grep the org's repos for Terraform, Helm charts, and CI config that does not go through the platform. Each one is a user telling you what they needed and could not get. This is the most reliable requirements document in the company and nobody writes it down.

Instrument the golden path. Track where people drop out. If 60 percent of services that start onboarding do not reach production, the funnel has a specific leak and you can find it. Most platform teams cannot answer this because they only count completions.

Run office hours and take notes on questions, not answers. The distribution of questions is the roadmap. If the same question appears eight times in a month, that is not a documentation problem, it is a design problem — you built something that requires explanation.

Jobs to be done, not features to be shipped

The framing error is building capabilities rather than completing jobs. "We support Postgres provisioning" is a capability. "A team can go from no database to a production database with backups, monitoring, credentials rotated into their service, and a documented restore procedure, in one afternoon, without talking to us" is a job.

Capabilities compose badly. Six capabilities that each solve 80 percent of their step leave a user who must solve six 20-percents themselves, in the right order, with no map. That is worse than one end-to-end path that is opinionated and complete, which is why the golden path metaphor works when it is honoured and fails when it is a marketing term for a collection of Helm charts.

The test for whether you have shipped a job: can a new engineer complete it from the documentation, with no Slack messages, on their first day? If not, it is a capability and you are the missing integration step.

Golden paths need escape hatches or they become cages

The strongest tension in platform design. A path that handles every case is not a path, it is a configuration language with your logo on it. A path that handles only the common case blocks the teams whose problems are unusual — who are frequently the teams with the most business-critical workloads.

The resolution is a tiered contract, stated explicitly:

  • Paved path. Opinionated, minimal configuration, fully supported, upgraded for you, on-call covered by the platform team. Covers 80 percent of services.
  • Extended path. Escape hatches at defined seams — bring your own Dockerfile, override the generated manifest, add a custom sidecar. Supported, but you own what you overrode. Covers another 15 percent.
  • Off-path. Raw cloud access with guardrails: policy enforcement, cost allocation labels, network boundaries, and audit still apply. Not supported by the platform team. The remaining 5 percent.

Publishing this tiering does two things. It removes the fiction that everything must go through the platform, which was never true and which made teams hide their off-path work rather than declare it. And it makes the boundary observable — you can count what is in each tier, and a paved-path share that stops growing is a signal you can act on.

# platform-contract.yaml — declared per service, checked in CI
service: checkout-api
tier: extended
overrides:
  - build: custom-dockerfile      # multi-stage native deps
    owner: payments
    reason: "libvips build requirement, revisit Q3"
  - deploy: manifest-patch
    owner: payments
    reason: "custom PDB, quorum-sensitive"
support:
  platform: [runtime, networking, observability, secrets]
  team:     [build, deployment-manifest]

Every override carries an owner and a reason. Review them quarterly. An override that eleven teams have applied for the same reason is not an escape hatch, it is a missing feature with a queue of validated demand, and it should be the top of the roadmap.

The three habits infrastructure teams have to unlearn

Building for the hardest user first. Infrastructure culture optimises for the most demanding case, because that is what reliability work rewards. Product work is the opposite: ship for the common case, get it adopted, then generalise with real evidence about which direction to generalise in. A platform that launches with support for every workload class in the company launches eighteen months late to users who have already built something else.

Treating deprecation as a technical migration. Removing the old path is the most political work a platform team does and it is consistently under-resourced. Budget for it explicitly — a deprecation without a named owner, a date, a migration tool, and an executive who will hold the date is a permanent second system. Running two paths forever costs more than either.

Measuring the platform's own health instead of its users' outcomes. Platform uptime is table stakes. The outcomes that justify the team's existence are delivery-shaped: lead time for change, deployment frequency, change failure rate, and time to restore, measured for the teams on the platform versus those off it. If you cannot show a difference, you have not yet made the case, no matter how good the internals are.

Cost belongs in that outcome set too. A platform that makes it easy to provision a service and invisible what that service costs has created a new problem while solving an old one. Wiring allocation labels and a cost signal into the paved path from the start is far cheaper than retrofitting it, and it is the mechanism that keeps a platform from becoming the place where spend goes to become unattributable.

The uncomfortable summary: most platform teams should ship less, talk to users more, and spend a third of their capacity on adoption and migration work that does not look like engineering. The teams that do this have platforms people choose. The teams that do not have platforms people are assigned to, which is a very different thing and rarely survives the next reorg.