Platform Maturity Assessment

Production engineering guide for platform maturity assessment covering patterns, implementation strategies, and operational best practices.

Platform Maturity Assessment evaluates the evolution and capability of a platform engineering function within an organisation. It identifies gaps, tracks progress, and guides investment by measuring how effectively platform services support developer productivity, system reliability, and operational efficiency. Use this assessment when onboarding a new team, before major platform rearchitecture, after a significant incident, or as a recurring audit to align platform strategy with developer needs.

Assessing Platform Maturity: A Step-by-Step Guide

The assessment is not a one-off survey but a hands-on exploration of platform artifacts, workflows, and developer interactions. Start by defining the scope: which teams, services, and platforms are in scope? Then gather evidence through a series of targeted checks, each revealing a dimension of maturity.

1. Platform Discovery and Visibility

Begin by identifying all platform components in use. The platform is only as good as its discoverability. A mature platform is self-documenting and easily navigable.

  apiVersion: platform.example/v1
  kind: PlatformService
  metadata:
    name: auth-service
    namespace: platform
  spec:
    displayName: "Authentication Service"
    description: "User login, token management, and SSO."
    owner: "[email protected]"
    documentation: "https://docs.example.com/platform/auth"
    tags:
      - "identity"
      - "security"
      - "api"

Silent failure: PlatformService resources exist but are not synced to the portal. The portal queries a database, and platform_service entries are not updated after kubectl apply -f auth-service.yaml. The root cause is a missing watch in the sync controller. A kubectl logs -l app=platform-portal-sync reveals:

failed to update service auth-service: failed to fetch documentation from https://docs.example.com/platform/auth: 404 Not Found

This indicates the documentation URL is incorrect or the service is not deployed.

2. Developer Onboarding and Self-Service

A mature platform empowers developers to onboard and deploy services with minimal platform team intervention.

The critical check: make deploy must be idempotent and predictable. Run it twice and observe no changes.

Failure mode: make deploy fails the second time. Inspection shows:

$ make deploy
INFO: deploying auth-service to production
INFO: creating namespace production
INFO: applying kustomization
Error: failed to apply kustomization: exit status 1
stderr:
Error: failed to apply manifests: failed to create service: Service "auth-service" already exists

The root cause is that kustomize build k8s/ does not include name in Service manifest, so kubectl apply treats auth-service as a new resource even when it exists.

Fix: ensure kustomization.yaml includes:

resources:
  - base/
patchesStrategicMerge:
  - service.yaml
namePrefix: auth-service-

Now make deploy is idempotent.

3. Golden Paths and Standard Workflows

Assess how well platform standards are enforced through golden paths.

Example ci.yaml:

name: Deploy Service
on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build Docker Image
        run: docker build -t ghcr.io/example/auth-service:$GITHUB_SHA .
      - name: Push Image
        run: |
          docker push ghcr.io/example/auth-service:$GITHUB_SHA
          echo "IMAGE=$GITHUB_SHA" >> $GITHUB_ENV

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to Production
        run: |
          kubectl set image deployment/auth-service \
            auth-service=ghcr.io/example/auth-service:$IMAGE \
            --namespace=production

The platform is mature when ci.yaml is a standard across all services, and new teams copy it with minimal changes.

Failure mode: deploy job fails due to missing IMAGE environment variable. The deploy job runs kubectl set image, but IMAGE is not set. The deploy job logs show:

Error: failed to apply deployment: error: no such file or directory

The root cause is that echo "IMAGE=$IMAGE" >> $GITHUB_ENV runs in a shell that does not inherit GITHUB_ENV from build. The fix is to use env: in the deploy job:

deploy:
  needs: build
  runs-on: ubuntu-latest
  env:
    IMAGE: ${{ secrets.IMAGE }}
  steps:
    - uses: actions/checkout@v3
    - name: Deploy to Production
      run: |
        kubectl set image deployment/auth-service \
          auth-service=ghcr.io/example/auth-service:$IMAGE \
          --namespace=production

4. Platform Observability and Incident Response

A mature platform provides immediate visibility into service health and enables rapid incident response.

  curl -s http://auth-service.example.com/metrics | grep "http_request_duration_seconds"
  curl -s 'http://prometheus.example.com/api/v1/query?query=http_request_duration_seconds_count{job="auth-service"}'
  {
    "status": "UP",
    "details": {
      "database": {
        "status": "UP",
        "details": {
          "connection": "OK",
          "latency": 12.4
        }
      },
      "cache": {
        "status": "UP",
        "details": {
          "ping": "OK",
          "hits": 98.2
        }
      }
    }
  }
  {
    "timestamp": "2024-04-15T12:34:56Z",
    "level": "info",
    "message": "User login successful",
    "user_id": 12345,
    "duration_ms": 42
  }

Silent failure: health endpoint returns {"status": "UP"} but details are missing. The platform defines a HealthCheck interface, but services implement it inconsistently. One service returns details as a map[string]string, another as []string.

The fix: standardize the HealthCheck contract in a common-health Go module. Services must export HealthCheck struct with:

type HealthCheck struct {
    Status  string            `json:"status"`
    Details map[string]Detail `json:"details"`
}

type Detail struct {
    Status  string  `json:"status"`
    Details map[string]any `json:"details"`
}

Now the central dashboard consumes health responses uniformly.

5. Platform Governance and Feedback Loops

A mature platform includes mechanisms for feedback, governance, and evolution.

  curl -X POST \
    -H "Content-Type: application/json" \
    -d '{
      "title": "Platform feature request: auto-scaling for auth-service",
      "body": "We need auto-scaling based on JWT token load.",
      "labels": ["platform", "feature"]
    }' \
    https://api.github.com/repos/example/auth-service/issues
  curl -H "Accept: application/json" \
    https://api.github.com/repos/example/platform/issues?labels=platform,review

Failure mode: reviews are not linked to issues. A review-2024-04-01.md is created, but the GitHub issue has no link. The root cause is that the platform-review tool expects a review-id field in the YAML header:

---
reviewer: [email protected]
service: auth-service
date: 2024-04-01
review-id: 1234
---

Without review-id, the tool does not update the issue.

6. Platform Maturity Scoring

After gathering evidence, score the platform using a rubric of five levels: Novice, Apprentice, Journeyman, Expert, Master.

Each level is defined by the presence and consistency of practices:

The assessment is complete when all evidence points to a single level. The next step is to define actions to move to the next level.

This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.