ЁЯПл The SchoolтА║ЁЯЫдя╕П Platform EngineeringтА║ЁЯПЕ рдзрдбрд╛ 10 тАФ Scorecards рдЖрдгрд┐ maturity: рдкреНрд░рддреНрдпреЗрдХ рд╡рд░реНрдЧрдЦреЛрд▓реАрд╕рд╛рдареА рддрдпрд╛рд░реАрдЪреА рддрдкрд╛рд╕рдгреА-рдпрд╛рджреА
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯПЕ рдзрдбрд╛ 10 тАФ Scorecards рдЖрдгрд┐ maturity: рдкреНрд░рддреНрдпреЗрдХ рд╡рд░реНрдЧрдЦреЛрд▓реАрд╕рд╛рдареА рддрдпрд╛рд░реАрдЪреА рддрдкрд╛рд╕рдгреА-рдпрд╛рджреА

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 10 ┬╖ рдорд╛рдЧреАрд▓: lesson-09-policy-guardrails ┬╖ рдкреБрдвреАрд▓: lesson-11-measuring


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ09, рдЖрдгрд┐ scorecards: рдкреНрд░рддреНрдпреЗрдХ service рд╡рд░ рдЪрд╛рд▓рд╡рд▓реА рдЬрд╛рдгрд╛рд░реА production-readiness рддрдкрд╛рд╕рдгреНрдпрд╛рдВрдЪреА weighted рдпрд╛рджреА, рдЬрд┐рдЪреЗ рд░реВрдкрд╛рдВрддрд░ рдЯрдХреНрдХреЗрд╡рд╛рд░реА рдЖрдгрд┐ level рдордзреНрдпреЗ рд╣реЛрддреЗ (gold, silver, bronze, not ready), рдЖрдгрд┐ тАФ рд╕рд░реНрд╡рд╛рдд рдЙрдкрдпреЛрдЧреА тАФ рдкреБрдвреЗ рдХрд╛рдп рджреБрд░реБрд╕реНрдд рдХрд░рд╛рдпрдЪреЗ рддреЗ. CHECKS рдЖрдгрд┐ score() idp/guard.py рдордзреНрдпреЗ, scorecards() idp/demo.py рдордзреНрдпреЗ.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

Policies (рдзрдбрд╛ 09) рд╣реЗ рдЕрд╕рд▓реЗрдЪ рдкрд╛рд╣рд┐рдЬреЗ рдЕрд╕реЗ рдирд┐рдпрдо рдЖрд╣реЗрдд: fire exit рдЕрдбрд╡рд▓реЗрд▓реА рдЕрд╕реЗрд▓ рддрд░ рдХреЛрдгрддреАрд╣реА рдЦреЛрд▓реА рдЙрдШрдбрдд рдирд╛рд╣реА. рдкрдг рдЕрд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ рдЕрд╢рд╛ рдЕрдиреЗрдХ рдЧреЛрд╖реНрдЯреАрд╣реА рдЖрд╣реЗрдд: рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдд рдПрдХ рдЬрд╛рджрд╛ рдХрд┐рд▓реНрд▓реА, рджрд╛рд░рд╛рд╡рд░ рдХреЛрдгрд╛рд▓рд╛ рдмреЛрд▓рд╡рд╛рдпрдЪреЗ рддреЗ рд╕рд╛рдВрдЧрдгрд╛рд░реА рдЪрд┐рдареНрдареА, heating рдмрдВрдж рдкрдбрд▓реЗ рддрд░ рдХрд╛рдп рдХрд░рд╛рдпрдЪреЗ рдпрд╛рдЪрд╛ рдЖрд░рд╛рдЦрдбрд╛.

рдореНрд╣рдгреВрди рд╕реБрд╡рд┐рдзрд╛ рдХрд╛рд░реНрдпрд╛рд▓рдп рдкреНрд░рддреНрдпреЗрдХ рд╡рд░реНрдЧрдЦреЛрд▓реАрд╕рд╛рдареА рдПрдХ рддрдпрд╛рд░реА-card рдареЗрд╡рддреЗ. ЁЯПЕ рдЖрда рддрдкрд╛рд╕рдгреНрдпрд╛. рдорд╣рддреНрддреНрд╡рд╛рдЪреНрдпрд╛ рддрдкрд╛рд╕рдгреНрдпрд╛ рджреБрдкреНрдкрдЯ рдореЛрдЬрд▓реНрдпрд╛ рдЬрд╛рддрд╛рдд: owner, on call рдЕрд╕рд▓реЗрд▓реА рд╡реНрдпрдХреНрддреА, рдЪрд╛рд▓рдгрд╛рд░реЗ alarms, рдХреЛрдгрддреЗрд╣реА рдорд╛рд╣реАрдд рдЕрд╕рд▓реЗрд▓реЗ рдзреЛрдХрд╛рджрд╛рдпрдХ рджреЛрд╖ рдирд╛рд╣реАрдд. рдкреНрд░рддреНрдпреЗрдХ рдЦреЛрд▓реАрд▓рд╛ рдЧреБрдг рдЖрдгрд┐ рдПрдХ рдмрд┐рд▓реНрд▓рд╛ рдорд┐рд│рддреЛ.

рдХреЛрдгрд╛рд▓рд╛рд╣реА рд▓рд╛рдЬрд╡рдгреНрдпрд╛рд╕рд╛рдареА рджреАрдкрд┐рдХрд╛ рд╣реЗ рдЧреБрдг staff-room рдЪреНрдпрд╛ рднрд┐рдВрддреАрд╡рд░ рд▓рд╛рд╡рдд рдирд╛рд╣реА. рдкреНрд░рддреНрдпреЗрдХ рд╢рд┐рдХреНрд╖рд┐рдХреЗрд▓рд╛ рддрд┐рдЪреЗ рд╕реНрд╡рддрдГрдЪреЗ card рдЖрдгрд┐ рдПрдХ рдкреБрдврдЪреА рдкрд╛рдпрд░реА рджрд┐рд╕рддреЗ. Fees рдиреЗ рддреАрди рдЧреЛрд╖реНрдЯреА рджреБрд░реБрд╕реНрдд рдХреЗрд▓реНрдпрд╛ рдЖрдгрд┐ рддреА bronze рд╡рд░реВрди silver рдЖрдгрд┐ рдордЧ gold рд╡рд░ рдЧреЗрд▓реА.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    c["ЁЯУЛ 8 checks ┬╖ total weight 12<br/>owner 2 ┬╖ on-call 2 ┬╖ alerts 2 ┬╖ no critical CVEs 2<br/>runbook 1 ┬╖ pipeline v2.x 1 ┬╖ SLO 1 ┬╖ deps 1"] --> s["ЁЯзо weighted %"]
    s --> l{"ЁЯПЕ level"}
    l --> g["ЁЯеЗ gold тЙе 90<br/>exam-results 92%"]
    l --> sv["ЁЯеИ silver тЙе 70<br/>timetable 83%"]
    l --> b["ЁЯеЙ bronze тЙе 50<br/>library-search 58% ┬╖ fees 50%"]
    l --> n["тЫФ not ready<br/>canteen-orders 33%"]

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/platform-engineering/lesson-diagrams.html#l10

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рдирд╛рд╣реАрддрд░ "рд╣реА service production ready рдЖрд╣реЗ рдХрд╛?" рдпрд╛рдЪреЗ рдЙрддреНрддрд░ рдЕрдВрджрд╛рдЬрд╛рдиреЗ, рдПрдХрджрд╛рдЪ, launch рдЪреНрдпрд╛ рд╡реЗрд│реА рджрд┐рд▓реЗ рдЬрд╛рддреЗ, рдЖрдгрд┐ рдкреБрдиреНрд╣рд╛ рдХрдзреАрдЪ рдирд╛рд╣реА. Scorecard рдкреНрд░рддреНрдпреЗрдХ service рд▓рд╛ рддреЗрдЪ рдкреНрд░рд╢реНрди, рд╕рддрдд, platform рдХрдбреЗ рдЖрдзреАрдЪ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ data рд╡рд░реВрди рд╡рд┐рдЪрд╛рд░рддреЛ (catalog, pipeline version, vulnerability scan). рддреЛ teams рдирд╛ рддреНрдпрд╛ рдХреБрдареЗ рдЖрд╣реЗрдд рддреЗ рджрд╛рдЦрд╡рддреЛ рдЖрдгрд┐ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рд▓рд╛ platform рдиреЗ рдХреБрдареЗ рдорджрдд рдХрд░рд╛рдпрд▓рд╛ рд╣рд╡реА рддреЗ тАФ рдЬрд░ рдЕрд░реНрдзреНрдпрд╛ services рдордзреНрдпреЗ "alerts defined" рдирд╕реЗрд▓, рддрд░ рддреЛ рдПрдХ рдЧрд╣рд╛рд│ kit рдЖрд╣реЗ, рдкрдиреНрдирд╛рд╕ рдЖрд│рд╢реА teams рдирд╛рд╣реАрдд.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

idp/guard.py рдордзреАрд▓ CHECKS рд╣реА (check, weight) рдЪреА рдпрд╛рджреА рдЖрд╣реЗ, рдПрдХреВрдг weight 12. score(passed) рдкрд╛рд╕ рдЭрд╛рд▓реЗрд▓реНрдпрд╛ checks рдЪреЗ weights рдмреЗрд░реАрдЬ рдХрд░рддреЛ, 12 рдиреЗ рднрд╛рдЧрддреЛ, рдкреВрд░реНрдг рдЯрдХреНрдХреНрдпрд╛рдкрд░реНрдпрдВрдд round рдХрд░рддреЛ, level рдирд┐рд╡рдбрддреЛ, рдЖрдгрд┐ рдЕрдкреВрд░реНрдг checks рд╕рд░реНрд╡рд╛рдд рдЬрдб рдЖрдзреА рдЕрд╢рд╛ рдХреНрд░рдорд╛рдиреЗ рджреЗрддреЛ тАФ рдореНрд╣рдгрдЬреЗ missing[0] рд╣реАрдЪ рдкреБрдврдЪреА рдкрд╛рдпрд░реА. idp/demo.py рдордзреАрд▓ scorecards() catalog рдордзреАрд▓ рдкрд╛рдЪ services рдирд╛ рдЧреБрдг рджреЗрддреЛ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 idp/demo.py scorecards
python3 - <<'EOF'
import sys; sys.path.insert(0, "idp"); from guard import CHECKS, score
everything = {c for c, _ in CHECKS}
fees = everything - {"has an owner", "on-call rota set", "no critical CVEs"}
print("fees today:", score(fees))
for fix in ("has an owner", "on-call rota set", "no critical CVEs"):
    fees = fees | {fix}; pct, level, missing = score(fees)
    print(f"+ {fix:<17} тЖТ {pct:>3}% {level}")
print("only light checks:", score({"has a runbook", "pipeline on v2.x", "SLO written", "dependencies declared"})[:2])
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

scorecards рд╣реЗ рдЫрд╛рдкрддреЗ:

тФАтФА production readiness: 8 weighted checks (total weight 12) ┬╖ gold тЙе 90 ┬╖ silver тЙе 70 ┬╖ bronze тЙе 50
   exam-results     92% gold      next: SLO written
   timetable        83% silver    next: has a runbook
   library-search   58% bronze    next: on-call rota set
   fees             50% bronze    next: has an owner
   canteen-orders   33% not ready next: has an owner

рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:

fees today: (50, 'bronze', ['has an owner', 'on-call rota set', 'no critical CVEs'])
+ has an owner      тЖТ  67% bronze
+ on-call rota set  тЖТ  83% silver
+ no critical CVEs  тЖТ 100% gold

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

Fees рддреАрди рдкрд╛рдпрд▒реНрдпрд╛рдВрдд 50% рд╡рд░реВрди 100% рд╡рд░ рдЧреЗрд▓реА, рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рдпрд░реА card рдиреЗрдЪ рд╕реБрдЪрд╡рд▓реА. рдЪрд╛рд░ checks тАФ рдлрдХреНрдд рд╣рд▓рдХреЗ тАФ рдкрд╛рд╕ рдХрд░рдгрд╛рд▒реНрдпрд╛ service рд▓рд╛ 33% рдорд┐рд│рддрд╛рдд рдЖрдгрд┐ рддреА "not ready" рдард░рддреЗ: weights рдореБрд│реЗ runbook рдЖрдгрд┐ SLO рдЧрд╣рд╛рд│ owner рдЖрдгрд┐ on-call рд▓рдкрд╡реВ рд╢рдХрдд рдирд╛рд╣реАрдд. рдзрдбрд╛ 04 рдордзреАрд▓ рджреЛрди orphans (fees, canteen-orders) рддрд│рд╛рд╢реА рдЖрд╣реЗрдд, рддреНрдпрд╛рдЪ рдХрд╛рд░рдгрд╛рдиреЗ рдЬреНрдпрд╛рд╕рд╛рдареА рддреНрдпрд╛рдВрдирд╛ рддрд┐рдереЗ рдЦреВрдг рдХреЗрд▓реА рд╣реЛрддреА: owner рдирд╛рд╣реА. Catalog, pipeline version (рдзрдбрд╛ 07) рдЖрдгрд┐ scan рдЪреЗ рдирд┐рдХрд╛рд▓ рдПрдХрд╛рдЪ card рдордзреНрдпреЗ рдпреЗрддрд╛рдд.

ЁЯУП рд╢рд┐рдХрд╡рдгреНрдпрд╛рд╕рд╛рдареАрдЪрд╛ рдирдореБрдирд╛: рдЦрд░реЗ scorecards рдкреНрд░рддреНрдпреЗрдХ check live data рд╡рд░реВрди рдореЛрдЬрддрд╛рдд (catalog, CI, scanner, paging tool). рдЗрдереЗ рдкрд╛рд╕ рдЭрд╛рд▓реЗрд▓реЗ checks рдПрдХ set рдореНрд╣рдгреВрди рджрд┐рд▓реЗ рдЖрд╣реЗрдд.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

Backstage рдордзреНрдпреЗ, open-source Tech Insights plugin рдкреНрд░рддреНрдпреЗрдХ entity рдмрджреНрджрд▓ рдард░рд▓реЗрд▓реНрдпрд╛ рд╡реЗрд│рд╛рдкрддреНрд░рдХрд╛рдиреЗ facts рдЧреЛрд│рд╛ рдХрд░рддреЗ (рдЙрджрд╛. "has an owner", "has TechDocs") рдЖрдгрд┐ рддреНрдпрд╛ facts рд╡рд░ checks рддрдкрд╛рд╕рддреЗ; рддреБрдордЪреНрдпрд╛ version рд╕рд╛рдареАрдЪреЗ configuration рддреНрдпрд╛рдЪреНрдпрд╛ documentation рдордзреНрдпреЗ рджрд┐рд▓реЗ рдЖрд╣реЗ.

Port рдордзреНрдпреЗ, scorecard рдПрдХрд╛ blueprint (entity type) рдЪрд╛ рднрд╛рдЧ рдЕрд╕рддреЛ рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ rule рд▓рд╛ рдПрдХ level рдЖрдгрд┐ entity рдЪреНрдпрд╛ properties рд╡рд░ рдЕрдЯреА рдЕрд╕рддрд╛рдд. Tool рдХреЛрдгрддреЗрд╣реА рдЕрд╕реЛ, scorecard рддреНрдпрд╛рдорд╛рдЧрдЪреНрдпрд╛ data рдЗрддрдХрд╛рдЪ рдЪрд╛рдВрдЧрд▓рд╛ рдЕрд╕рддреЛ тАФ рдореНрд╣рдгреВрди рдкрд╣рд┐рд▓реЗ рдХрд╛рдо рд╕рд╣рд╕рд╛ catalog рдкреВрд░реНрдг рдХрд░рдгреЗ рд╣реЗ рдЕрд╕рддреЗ (рдзрдбрд╛ 04).

рддреБрдордЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ export рдордзреВрди рд╕рдЧрд│реНрдпрд╛ services рдордзрд▓реА рд╕рд░реНрд╡рд╛рдд рд╕рд╛рдорд╛рдиреНрдп рдЙрдгреАрд╡ рдкрдЯрдХрди рдкрд╛рд╣рдгреНрдпрд╛рдЪрд╛ рдорд╛рд░реНрдЧ:

# on a real account: scores.csv from your portal тАФ service,check,passed
awk -F, '$3=="false"{miss[$2]++} END{for (c in miss) print miss[c], c}' scores.csv | sort -rn | head -5

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдЬреНрдпрд╛ check рдордзреНрдпреЗ рдмрд╣реБрддреЗрдХ services рдирд╛рдкрд╛рд╕ рд╣реЛрддрд╛рдд, рддреЛрдЪ рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдЪрд╛ рдкреБрдврдЪрд╛ kit рдЖрд╣реЗ. Scorecards service teams рдЗрддрдХреЗрдЪ platform team рд╕рд╛рдареАрд╣реА feedback рдЖрд╣реЗрдд.

тПня╕П рдкреБрдвреЗ

Scorecards services рдореЛрдЬрддрд╛рдд. рдкреБрдвреЗ: рдХрд╛рд░реНрдпрд╛рд▓рдпрд╛рдЪреЗрдЪ рдореЛрдЬрдорд╛рдк тАФ platform рдореБрд│реЗ delivery рдЬрд▓рдж рдЖрдгрд┐ рд╕реБрд░рдХреНрд╖рд┐рдд рд╣реЛрдд рдЖрд╣реЗ рдХрд╛, рдЖрдгрд┐ рдХреЛрдгрд╛рд▓рд╛рд╣реА рд╣рд╛рдиреА рди рдкреЛрд╣реЛрдЪрд╡рддрд╛ рддреЗ рдХрд╕реЗ рдореЛрдЬрд╛рдпрдЪреЗ.

git checkout lesson-11-measuring

ЁЯПЕ Lesson 10 тАФ Scorecards & maturity: a readiness checklist per classroom

ЁЯУН You are here: Lesson 10 of 12 ┬╖ Previous: lesson-09-policy-guardrails ┬╖ Next: lesson-11-measuring


ЁЯУж What's in this branch

Lessons 01тАУ09, plus scorecards: a weighted checklist of production-readiness checks run against every service, turned into a percentage and a level (gold, silver, bronze, not ready), and тАФ most useful тАФ the next thing to fix. CHECKS and score() in idp/guard.py, scorecards() in idp/demo.py.

ЁЯзТ Explain like I'm 5

Policies (lesson 09) are the must rules: no room opens with a blocked fire exit. But there are many should things too: a spare key with the office, a note on the door saying who to call, a plan for when the heating breaks.

So the facilities office keeps a readiness card for every classroom. ЁЯПЕ Eight checks. The important ones count double: an owner, a person on call, alarms that work, no known dangerous faults. Each room gets a score and a badge.

Dipika does not pin the scores on the staff-room wall to embarrass anyone. Each teacher sees her own card and the one next step. Fees fixed three things and went from bronze to silver to gold.

ЁЯЧ║я╕П Diagram

flowchart LR
    c["ЁЯУЛ 8 checks ┬╖ total weight 12<br/>owner 2 ┬╖ on-call 2 ┬╖ alerts 2 ┬╖ no critical CVEs 2<br/>runbook 1 ┬╖ pipeline v2.x 1 ┬╖ SLO 1 ┬╖ deps 1"] --> s["ЁЯзо weighted %"]
    s --> l{"ЁЯПЕ level"}
    l --> g["ЁЯеЗ gold тЙе 90<br/>exam-results 92%"]
    l --> sv["ЁЯеИ silver тЙе 70<br/>timetable 83%"]
    l --> b["ЁЯеЙ bronze тЙе 50<br/>library-search 58% ┬╖ fees 50%"]
    l --> n["тЫФ not ready<br/>canteen-orders 33%"]

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/platform-engineering/lesson-diagrams.html#l10

тЭУ What

ЁЯдФ Why

Because "is this service production ready?" is otherwise answered by gut feeling, once, at launch, and never again. A scorecard asks the same questions of every service, all the time, from data the platform already has (the catalog, the pipeline version, the vulnerability scan). It shows teams where they stand and the office where the platform should help тАФ if half the services miss "alerts defined", that is a missing kit, not fifty lazy teams.

ЁЯФз How (in this repo)

CHECKS in idp/guard.py is a list of (check, weight) with total weight 12. score(passed) adds the weights of the passed checks, divides by 12, rounds to a whole percent, picks the level, and lists the missing checks heaviest first тАФ so missing[0] is the next step. scorecards() in idp/demo.py scores five services from the catalog.

ЁЯзк Try it

python3 idp/demo.py scorecards
python3 - <<'EOF'
import sys; sys.path.insert(0, "idp"); from guard import CHECKS, score
everything = {c for c, _ in CHECKS}
fees = everything - {"has an owner", "on-call rota set", "no critical CVEs"}
print("fees today:", score(fees))
for fix in ("has an owner", "on-call rota set", "no critical CVEs"):
    fees = fees | {fix}; pct, level, missing = score(fees)
    print(f"+ {fix:<17} тЖТ {pct:>3}% {level}")
print("only light checks:", score({"has a runbook", "pipeline on v2.x", "SLO written", "dependencies declared"})[:2])
EOF

тЬЕ Verify тАФ what you should see

scorecards prints:

тФАтФА production readiness: 8 weighted checks (total weight 12) ┬╖ gold тЙе 90 ┬╖ silver тЙе 70 ┬╖ bronze тЙе 50
   exam-results     92% gold      next: SLO written
   timetable        83% silver    next: has a runbook
   library-search   58% bronze    next: on-call rota set
   fees             50% bronze    next: has an owner
   canteen-orders   33% not ready next: has an owner

Your snippet prints:

fees today: (50, 'bronze', ['has an owner', 'on-call rota set', 'no critical CVEs'])
+ has an owner      тЖТ  67% bronze
+ on-call rota set  тЖТ  83% silver
+ no critical CVEs  тЖТ 100% gold

ЁЯПБ What you just proved

Fees went from 50% to 100% in three steps, each suggested by the card itself. A service that passes four checks тАФ only the light ones тАФ scores 33% and is "not ready": the weights make sure a runbook and an SLO cannot hide a missing owner and on-call. The two orphans from lesson 04 (fees, canteen-orders) are at the bottom for the same reason they were flagged there: no owner. The catalog, the pipeline version (lesson 07) and the scan results feed one card.

ЁЯУП Teaching model: real scorecards compute each check from live data (the catalog, CI, the scanner, the paging tool). Here the passed checks are given as a set.

тЪая╕П Common mistakes

ЁЯПн In production

In Backstage, the open-source Tech Insights plugin collects facts about each entity on a schedule (for example, "has an owner", "has TechDocs") and evaluates checks on those facts; its documentation shows the configuration for your version.

In Port, a scorecard belongs to a blueprint (an entity type) and each rule has a level and conditions on the entity's properties. Whatever the tool, the scorecard is only as good as the data behind it тАФ so the first work is usually making the catalog complete (lesson 04).

A quick way to see the most common gap across all services from your own export:

# on a real account: scores.csv from your portal тАФ service,check,passed
awk -F, '$3=="false"{miss[$2]++} END{for (c in miss) print miss[c], c}' scores.csv | sort -rn | head -5

ЁЯПн Why this matters in production: the check most services fail is the office's next kit. Scorecards are feedback for the platform team as much as for the service teams.

тПня╕П Next

Scorecards measure services. Next: measuring the office itself тАФ is the platform making delivery faster and safer, and how to measure that without harming anyone.

git checkout lesson-11-measuring
тЖР Previouspolicy guardrailsNext тЖТmeasuring

This page is the lesson's README from the lesson-10-scorecards branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.