Skip to main content

Command Palette

Search for a command to run...

Grade the golden path: an offline production-readiness scorecard for any repo

Internal developer platforms turned "is this service production-ready?" into a scorecard question. gradepath answers it from a checkout alone - a weighted golden-path checklist that prints a grade and the exact gaps to close, with no platform, network, or AI.

Updated
9 min readView as Markdown
Grade the golden path: an offline production-readiness scorecard for any repo
J
Cloud & Platform Engineer focused on building systems that scale and endure. I explore how infrastructure, automation, and engineering practices come together to support modern software teams.

Every platform team eventually writes the same document. It has a title like "Definition of Done for a Service" or "Production Readiness Review," and it lists the things a repo needs before anyone will put it on call: CI, tests, a real README, a license, a container image, some logs and metrics, a security contact, a changelog. Then the document goes stale, because nothing checks it. The list lives in a wiki; the repos drift; and the only time anyone notices a service was never actually ready is during the incident.

Internal Developer Platforms tried to fix this with scorecards - Backstage's software health checks, Cortex, OpsLevel. They're good, and they're heavy: a catalog, integrations, a running control plane, a YAML entity for every service. That's a lot of machinery to answer a question you often want to ask about a single checkout, right now, on your laptop or in a pull request.

gradepath is the small, offline version of that question. Point it at a directory and it scans for the presence and basic quality of production-readiness signals, applies a weighted checklist, and prints a maturity grade with a prioritized list of the gaps to close - heaviest first. No catalog, no network, no execution, no AI. One Go binary over a filesystem.

$ gradepath ./services/orders

gradepath  service production-readiness scorecard

  GRADE  B   78.5/100   (production-ready)
  13 passed · 1 partial · 3 missing  of 17 checks

  ● gaps to close (weighted, highest impact first)
    ✗ Security policy                (+5 pts)
       ↳ Add SECURITY.md with a vulnerability-disclosure process.
    ✗ Changelog maintained           (+4 pts)
       ↳ Keep a CHANGELOG.md so consumers can see what changed between releases.
    ~ Logging / metrics / tracing    (+2.5 pts)
       ↳ Wire structured logging plus metrics or tracing.

A scorecard is a producer, not a linter

Most of the small tools I build are gates: they look for one specific problem and exit non-zero so a pre-commit hook or CI turns red. That model is exactly wrong for a readiness score. A grade isn't pass/fail - it's a position on a spectrum, and its job is to inform prioritization, not to block a merge.

So gradepath is a producer. By default it always exits 0 and simply reports. The value is in the report: the grade tells you where the service sits, and the ranked gaps tell you the shortest route up. If you do want a gate - say, "new services must reach 75 before they ship" - you opt in with --min-score N, and only then does a low score exit 1.

gradepath .                    # always exit 0 - pure report
gradepath --min-score 75 .     # exit 1 if below 75 - an opt-in CI gate

That single design decision - report by default, gate by choice - is what makes a scorecard usable across a hundred repos without creating a hundred red builds on day one.

The scoring model

The core is deliberately boring, because a grade people will act on has to be explainable in one breath.

Every check on the checklist has a weight and returns one of three states:

  • pass - the signal is present and looks non-trivial → full weight

  • partial - present but weak (a stub README, or only one of logging/metrics/tracing) → half weight

  • fail - missing → zero

The score is just the weighted percentage:

score (0..100) = Σ earned weight / Σ total weight × 100

and the grade is the highest tier whose cutoff the score clears:

Grade Score Tier
A ≥ 90 golden path
B ≥ 75 production-ready
C ≥ 60 maturing
D ≥ 40 early
F < 40 bare

The gaps list is simply the non-passing checks sorted by descending weight. That ordering is the whole point: it turns "you're missing eight things" into "fix these two first, they're worth the most."

What it actually looks for

Seventeen checks across eight categories. The heaviest signals are the ones whose absence most reliably says not production software:

Category Checks (weight)
CI/CD a CI pipeline - GitHub Actions, GitLab CI, Jenkins, CircleCI, Travis, Azure, Bitbucket (12)
Tests a tests dir or *_test.go / test_*.py / *.spec.ts (12); coverage tracked (4)
Docs a substantive README (10); CONTRIBUTING (4); docs/ (3)
Licensing a LICENSE file (8)
Containerization Dockerfile (6); .dockerignore (2); HEALTHCHECK or a /health endpoint (3)
Observability logging / metrics / tracing hints (5)
Security SECURITY.md (5); a dependency lockfile (5); no committed secrets (4)
Ops CHANGELOG (4); CODEOWNERS (3); release versioning (3)

A few of the detectors are more than a file-exists check:

  • README is graded on substance, not presence. A two-line stub is a partial; a README past a size threshold with real sections is a pass. The classic "we have a README" that says nothing doesn't get full marks.

  • Observability scans a bounded set of source files for structured-logging, metrics/tracing, and health-endpoint signals (slog, zap, Prometheus, OpenTelemetry, /healthz, …). Two of the three is a pass; one is a partial; none fails.

  • No committed secrets is an inverted check - it passes when it finds nothing, and fails if it spots a committed .env, id_rsa, *.pem, or credentials.json. It deliberately ignores .env.example and *.sample, because a template is a good thing, not a leak.

Everything is a read-only filesystem scan. gradepath never runs git, never executes the target code, never opens a socket. It walks the tree once, skipping .git, vendor, node_modules, and build output, indexes files by basename, and caches a bounded amount of doc/source/CI content for the detectors that need to read inside a file.

Honesty: presence is not correctness

The most important sentence in the README is the one admitting what gradepath doesn't do. It scores the presence of a signal, not its correctness. A Dockerfile counts even if it runs as root. A README is "substantive" by size and structure, not by whether it's accurate. The observability check sees that you imported a metrics library, not that your dashboards are any good.

This is on purpose. A holistic, offline, deterministic first pass that you can run on every repo in an org and rank by what to fix first is enormously useful - and it is a completely different thing from a security audit or a code review. gradepath is a map of the golden path, not a judge of the code that walks it. Selling it as more than that would be dishonest, and it would break the moment someone gamed a check with an empty file.

Your golden path, not mine

"Production-ready" means different things to a fintech API and an internal batch job. The default weights encode a reasonable general opinion, but they're just that - an opinion. So the entire checklist is overridable with --config (JSON): reweight checks, disable the ones you don't care about, and set your own grade cutoffs.

{
  "weights": { "ci_workflow": 20, "tests_present": 20, "codeowners": 0 },
  "disable": ["dockerignore"],
  "grades": [
    { "grade": "A", "min": 92, "tier": "golden path" },
    { "grade": "B", "min": 80, "tier": "production-ready" },
    { "grade": "F", "min": 0,  "tier": "needs work" }
  ]
}

A weight of 0 (or the disable list) turns a check off entirely; a team that doesn't containerize can drop the whole category. Custom grades replace the defaults wholesale. The point is that gradepath ships an opinion you can overrule, which is the only kind of opinion a platform tool should ship.

Two fixtures, two grades

The test suite pins the behavior against two repositories so the numbers can't silently drift.

The bare fixture is a lone main.go and a two-line README. It scores 9.7 / 100, grade F ("bare") - only the no-secrets check passes, the README is a partial, and every heavy signal is a ranked gap.

The well-equipped fixture has the lot: CI with coverage, a tests directory and a _test.go, a real README, CONTRIBUTING, docs/, a LICENSE, a Dockerfile with .dockerignore and a HEALTHCHECK, a /healthz + /metrics service using slog, a SECURITY policy, a lockfile, a CHANGELOG, CODEOWNERS, and a VERSION. It scores 100 / 100, grade A ("golden path") with zero gaps.

Those exact scores are assertions in the tests, alongside the --min-score gate (bare exits 1, well exits 0), a bad path exiting 2, and a config override that provably reduces the check count and lifts the score. The whole thing is stdlib-only Go, gofmt/go vet clean, and green on go test ./....

Distinct from the neighbors

gradepath sits next to a few focused tools I've written and is deliberately not any of them. Where those each flag one specific problem and fail - dev/AI shipping cruft left in a repo, a specific insecure production setting, .env.example drift - gradepath scores overall readiness across many categories and, by default, only reports. It's the holistic map, not the single tripwire; and unlike the hosted scorecard platforms, it needs no catalog, no integrations, and no network to run.

Try it

go install github.com/jay-tank/gradepath@latest
gradepath .

The source, the two fixtures, and the full checklist are on GitHub: github.com/jay-tank/gradepath (MIT-licensed). Grade a repo you own and see which two gaps are worth the most - that's the report doing its job.

More from this blog

J

Jay Tank's Engineering Blog

63 posts

Deep dives on running fintech & Web3 infrastructure at scale - AWS, Kubernetes, CI/CD, edge security, observability, and Bitcoin Lightning. Practical architecture breakdowns and open-source DevOps tools from a senior platform engineer.