
Delivery Manager
- 180 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Plan sprints, track dependencies, communicate status, and de-risk releases when shipping multi-team software with shifting priorities and stakeholder visibility needs.
About
Enables Claude to act as a delivery manager who structures backlogs, surfaces risks, coordinates dependencies, and produces crisp status updates so software teams ship on predictable timelines.
- Sprint and milestone planning
- Dependency and risk tracking
- Stakeholder status reporting
- Release readiness checklists
- Scope tradeoff facilitation
Delivery Manager by the numbers
- 180 all-time installs (skills.sh)
- Ranked #1,093 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/borghei/claude-skills --skill delivery-managerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 180 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Plan sprints, track dependencies, communicate status, and de-risk releases when shipping multi-team software with shifting priorities and stakeholder visibility needs.
Files
Delivery Manager
The agent acts as an expert delivery manager coordinating continuous software delivery. It plans releases, selects deployment strategies, manages incidents, evaluates change requests, and tracks SLA compliance with error budget calculations.
Core Capabilities
- Delivery maturity assessment — locate the team on a 5-level scale (Manual → DevOps Excellence) and target one level at a time.
- Release planning — scope, exit criteria, rollout strategy, and a T-7/T-1/T-0/T+1 communication plan; Go/No-Go requires all exit criteria met.
- Deployment strategy — blue-green, canary, rolling, big-bang selection with matching rollback paths and canary success thresholds.
- Incident response — DETECT→TRIAGE→RESPOND→RESOLVE→REVIEW with SEV-1–SEV-4 severity, response times, and mandatory post-mortems.
- Change & SLA governance — CAB/Standard/Expedited/Emergency change types, SLA/error-budget burn-rate tracking, and DORA metrics.
When to Use
- Planning a release and running a Go/No-Go against exit criteria
- Choosing a deployment strategy and its rollback plan
- Responding to a production incident or running a post-mortem
- Evaluating a change request or calculating SLA/error-budget burn
- Assessing delivery maturity or interpreting DORA metrics
Clarify First
Before generating the plan or report, confirm these inputs. If any is unknown or vague, ASK — do not assume:
- [ ] Which task — release readiness/Go-No-Go, deployment strategy, incident response, or SLA/error-budget tracking (each is a different workflow and artifact)
- [ ] Exit criteria or SLA target — the bar the release or service is measured against (Go/No-Go requires all criteria met; SLA math needs the target)
- [ ] Deployment strategy — blue-green, canary, rolling, or big-bang, when shipping (sets the rollout gates and rollback path)
- [ ] Incident severity — SEV-1 through SEV-4, when responding (sets response time, escalation, and whether a post-mortem is mandatory)
Stop rule: ask only the 2-3 that most change the output. If the user says "just draft it," proceed and list your assumptions at the top of the artifact.
Quick Start
python scripts/release_checker.py --version v2.5.0 # release readiness vs exit criteria
python scripts/deploy.py --env production --strategy canary # coordinate a deployment
python scripts/sla_calculator.py --service portal --period month # SLA + error budget
python scripts/incident_report.py --id INC-2024-0125 # incident report from timelineTools
| Tool | Purpose | Command |
|---|---|---|
release_checker.py | Check release readiness against exit criteria | python scripts/release_checker.py --version v2.5.0 |
deploy.py | Coordinate deployment with selected strategy | python scripts/deploy.py --env production --strategy canary |
sla_calculator.py | Calculate SLA compliance and error budget | python scripts/sla_calculator.py --service portal --period month |
incident_report.py | Generate incident report from timeline data | python scripts/incident_report.py --id INC-2024-0125 |
References
references/release_process.md-- Delivery maturity levels, release planning + exit criteria, change-request types, the release-readiness example, DORA metrics, cross-skill integration, troubleshooting, and success criteria. Read when planning a release or improving the pipeline.references/deployment_patterns.md-- Blue-green, canary, rolling, and big-bang strategies with rollback paths and canary stage thresholds. Read when selecting how to ship.references/incident_management.md-- Severity matrix (SEV-1–SEV-4), the 5-step incident workflow, and post-mortem requirements. Read during incident triage and response.references/sla_management.md-- SLA framework, error-budget calculation example, and burn-rate freeze thresholds. Read when tracking reliability budgets.references/red-flags.md-- Bad-vs-good examples of delivery-management output. Read this to review a release/incident plan before committing to it.
Scope & Limitations
In Scope: Release planning and readiness assessment, deployment strategy selection and coordination, incident response process management, change request evaluation, SLA/error budget tracking, DORA metrics monitoring, post-mortem facilitation, delivery maturity assessment.
Out of Scope: Infrastructure provisioning and CI/CD pipeline engineering (hand off to DevOps/SRE), sprint-level planning and backlog management (hand off to scrum-master/), strategic program governance (hand off to program-manager/), feature prioritization and roadmapping (hand off to senior-pm/).
Limitations: Error budget calculations assume accurate incident duration tracking -- manual time entry introduces measurement error. Deployment strategies (blue-green, canary) require infrastructure support that the delivery manager recommends but does not implement. DORA metrics are trailing indicators; improvement requires upstream changes in engineering practices.
Integration Points
| Integration | Direction | What Flows |
|---|---|---|
scrum-master/ | SM -> DM | Sprint completion data, demo-ready confirmation, velocity for release sizing |
senior-pm/ | PM -> DM | Release calendar, stakeholder communication requirements |
program-manager/ | PgM -> DM | Cross-project release dependencies, milestone alignment |
jira-expert/ | Bidirectional | Release version tracking in Jira; deployment status field updates |
agile-coach/ | Coach -> DM | Delivery maturity assessment inputs, DevOps culture recommendations |
confluence-expert/ | DM -> Confluence | Post-mortem documentation, runbook maintenance, release notes publishing |
Example: Northwind SaaS — Coordinating a Multi-Team Black Friday Release
Real-world scenario showing how to apply this skill end-to-end.
Context
Northwind SaaS (Series-B logistics + payments platform) processes 12-15x normal volume during the week of Black Friday and Cyber Monday. The 2026 BF/CM window is 2026-11-27 to 2026-12-02. The product team has three releases that need to land before the freeze on 2026-11-21:
- Payments v3.2 — a new retry-policy engine to reduce false declines
- Logistics v4.0 — a major rewrite of the carrier-rate cache
- Identity v2.1 — multi-factor enrollment for merchant admin accounts
Three product teams. Three release trains. One shared incident response model. A single missed exit criterion in any one of them can blow the freeze window. The delivery-manager skill is being applied to plan the coordinated release, deployment strategies, rollback paths, and comms.
It is 2026-05-22; this is the early planning, 6 months out. The actual deploy will be 2026-11-19 (Wednesday before freeze).
Inputs
- 3 release trains, 3 owning EMs, 3 owning PMs
- Shared on-call rotation (SRE), 4 on-call engineers
- Production traffic profile: 7M req/day baseline, projected 90-100M req/day peak BF
- Existing maturity: Level 3 (continuous delivery, push-button deploys, but no automatic rollback)
- Constraint: code freeze at 2026-11-21 00:00 UTC; no deploys 11-21 through 12-03 except security patches
- Constraint: rollback must be possible within 5 minutes for any of the three releases
- VP Eng directive: "If we are not ready, we don't ship. The cost of a bad release on Black Friday is higher than the cost of slipping."
Applying the skill
1. Assessed maturity per team. Payments at Level 3, Logistics at Level 2 (still has a manual smoke test step), Identity at Level 3. Logistics' Level 2 forced a different rollout decision. 2. Picked deployment strategy per release. Payments and Identity get canary (Level 3). Logistics gets blue-green because the carrier-rate cache rewrite is high-risk and Level 2 maturity demands instant rollback. 3. Wrote one shared exit-criteria checklist. Every release uses the same checklist. No team-specific exceptions. This is the single biggest lever for coordinated releases. 4. Defined Go/No-Go gates at T-7 and T-1. Every team presents in the same 60-minute meeting. Any No-Go in any one team pulls the whole train. 5. Drafted rollback runbooks per release. Each runbook is testable; each was dry-run at least once in pre-production. 6. Customer comms split into 3 audiences. Merchants, internal support, internal exec. 7. Wrote the incident response model. During BF/CM, severity definitions shift. P3 becomes P2; P2 becomes P1. Three on-call engineers are dedicated to BF/CM volume only.
The artifact
================================================================
NORTHWIND BLACK FRIDAY 2026 — COORDINATED RELEASE PLAN
Window: Deploy 2026-11-19 (Wed); freeze 11-21 to 12-03
Owner: Delivery Manager
Sponsors: VP Eng, VP Product
Last update: 2026-05-22
================================================================
PART 1 — SCOPE PER RELEASE
[1] PAYMENTS v3.2 — Retry Policy Engine
Team: Payments (5 eng, 1 PM, 1 EM)
PM: Priya Rao
EM: Marcus Lee
Risk: MEDIUM. Touches the hot path; well-tested.
Goal: Reduce false declines by 4-6%.
Strategy: Canary
Feature flag: pmt.retry_v3.2.enabled (default off)
Rollback: Flag off + revert deploy (~3 min)
[2] LOGISTICS v4.0 — Carrier-Rate Cache Rewrite
Team: Logistics (8 eng, 1 PM, 1 EM)
PM: Tomas Lewandowski
EM: Yusuf Diallo
Risk: HIGH. Schema change + cache layer rewrite.
Last attempt 2 quarters ago was rolled back.
Goal: Carrier rate calculation latency p99
from 380ms -> <80ms.
Strategy: Blue-Green
Feature flag: N/A (architecture-level, not flaggable)
Rollback: Switch traffic blue<->green (<1 min)
[3] IDENTITY v2.1 — Merchant Admin MFA Enrollment
Team: Identity (4 eng, 1 PM, 1 EM)
PM: Maria Chen
EM: Sara Kim
Risk: LOW. Additive; no path removed.
Goal: Enable MFA enrollment for ~800 merchants.
Strategy: Canary
Feature flag: id.mfa_v2.1.enabled (default off, opt-in)
Rollback: Flag off (~30 sec)
PART 2 — SHARED EXIT CRITERIA CHECKLIST
EVERY release must satisfy ALL of the following before Go.
No release-specific exceptions.
Code & test
[ ] All P1/P2 bugs in scope resolved
[ ] Unit test coverage maintained or improved
[ ] Integration test suite passing on main
[ ] Load test at 10x baseline passed
[ ] Soak test (4 hours) passed on staging
[ ] Security scan clean (no new high/critical)
Operational
[ ] Runbook reviewed by SRE on-call
[ ] Rollback procedure dry-run within last 14 days
[ ] Monitoring + alerting wired before deploy
[ ] Dashboards published on shared SRE channel
[ ] On-call EM signed off on deploy plan
Comms
[ ] Release notes drafted
[ ] Customer notification drafted (if customer-visible)
[ ] Support team briefed (mandatory walkthrough)
[ ] Exec stakeholders notified (T-7 + T-1)
Compliance
[ ] PCI-DSS impact assessed (Payments only)
[ ] Data residency unchanged
[ ] Audit log entries for the deploy itself enabled
This is the SAME checklist for every team. If it does not
fit your release, the release is changing, not the checklist.
PART 3 — DEPLOYMENT STRATEGIES IN DETAIL
[1] PAYMENTS v3.2 — CANARY
Stage 1 1% traffic (5 selected non-merchant test accounts)
Monitor 60 min
Watch: payment_success_rate, decline_rate, p99 latency
Block if: any metric moves >0.5%
Stage 2 5% traffic (random selection across customer tiers)
Monitor 2 hours
Block if: payment_success_rate drops >0.2%
Stage 3 25% traffic
Monitor 4 hours
Block if: any metric breach
Stage 4 100% traffic
Soak for 24 hours before BF freeze begins
Total canary window: ~32 hours from start
Start time: 2026-11-17 02:00 UTC (Tuesday off-hours)
Full at: 2026-11-18 10:00 UTC
[2] LOGISTICS v4.0 — BLUE-GREEN
Blue: v3.9 (current, all traffic)
Green: v4.0 (deployed in parallel)
Step 1 Deploy v4.0 to Green env, NO traffic
Step 2 Smoke test Green via internal load generator
Step 3 Shift 1% production traffic to Green
Monitor 30 min
Step 4 Shift 10% to Green
Monitor 60 min
Step 5 Shift 50% to Green
Monitor 2 hours
Step 6 Shift 100% to Green
Blue remains warm for 24 hours
Step 7 Decommission Blue after 24 hours soak
Rollback: any breach -> shift all traffic Green->Blue <1 min
Start time: 2026-11-18 02:00 UTC
Full at: 2026-11-18 14:00 UTC
[3] IDENTITY v2.1 — CANARY
Stage 1 Flag on for 3 internal Northwind staff merchants
Monitor 24 hours
Acceptance: zero auth-flow incidents
Stage 2 Flag on for first 50 opt-in merchants
Monitor 24 hours
Stage 3 Flag on for all 800 merchants who opted in
Stage 4 Make MFA available (still opt-in) to all merchants
Start time: 2026-11-15 (gives 6-day soak window)
Full at: 2026-11-19
PART 4 — COORDINATED TIMELINE
T-30 (2026-10-20) Scope finalized for all 3 releases
T-21 (2026-10-29) Load + soak testing completed for all 3
T-14 (2026-11-05) Rollback dry-runs completed for all 3
T-7 (2026-11-12) GO/NO-GO meeting #1 (90 min)
Each team presents exit criteria status.
Any No-Go pulls that release (or all if
inter-dependent).
T-2 (2026-11-17) Identity canary begins (early start —
needs longest soak)
Payments canary begins
T-1 (2026-11-18) GO/NO-GO meeting #2 (60 min)
Logistics blue-green begins after meeting
T-0 (2026-11-19) All three releases at 100% by EOD
T+1 (2026-11-20) Soak day; no other changes; war room open
T+2 (2026-11-21) Code freeze begins 00:00 UTC
PART 5 — ROLLBACK CRITERIA & PROCEDURE
A rollback is triggered if ANY of the following observed:
- payment_success_rate drops >0.5% sustained 10 min
- carrier_rate_p99 exceeds 200ms sustained 5 min
- auth_success_rate drops >0.2% sustained 10 min
- any new error rate >1% in deploy-related code paths
- on-call EM judgment call (single-person authority)
Rollback decision authority:
Tier 1: On-call EM of the affected team can rollback their
OWN release without escalation.
Tier 2: If rollback of one release affects another (unlikely
but possible), delivery manager makes the call.
Tier 3: VP Eng informed within 15 minutes either way.
Rollback comms template (pre-written, fill-in-blanks):
- Internal Slack #incidents announce within 5 minutes
- Status page update within 15 minutes if customer-visible
- Exec page if Tier 2 or higher within 30 minutes
PART 6 — INCIDENT RESPONSE MODEL (BF/CM WINDOW)
During BF/CM, severity definitions ELEVATE by one level:
Normal time BF/CM time
P1 critical P0 - full-org war room
P2 major P1 - SRE + EM page
P3 minor P2 - business hours triage
P4 low P3 - backlog
Why: a "minor checkout glitch" in normal time is a brand
incident on Black Friday.
On-call structure:
- SRE lead (primary, paged first)
- Payments EM secondary
- Logistics EM secondary
- Identity EM secondary
- Delivery manager on-call for cross-team coordination
- VP Eng on call for executive decisions
Comms cadence during incident:
Internal Slack: every 15 min until resolved
Status page: every 30 min until resolved
Customer email: only if P0 sustained >2 hours
PART 7 — CUSTOMER COMMS
[A] PRE-RELEASE EMAIL TO MERCHANTS — 2026-11-12 (T-7)
To: All 12,400 active merchants
From: product@northwind.com
Subject: Improvements landing before Black Friday
Body:
Three updates roll out before our Black Friday freeze:
1. Smarter payment retries (no merchant action needed).
2. Faster carrier rate calculations on checkout.
3. New optional MFA for your admin accounts -- you
can enroll any time at /security/mfa.
Window: Nov 17-19. No expected downtime. Status page:
status.northwind.com.
[B] PRE-RELEASE BRIEF TO SUPPORT — 2026-11-13
Live walkthrough of all three releases, 90 minutes.
Includes: what changes for the merchant, what tickets
might increase, escalation path.
[C] EXEC PRE-RELEASE NOTE — 2026-11-18
1-page summary, what is shipping, what is at risk, what
the go/no-go decision was.
PART 8 — POST-FREEZE PROCEDURE
2026-12-03 00:00 UTC Freeze ends
2026-12-03 Post-mortem schedule sent
2026-12-05 BF/CM retro (cross-team)
Three required post-mortems regardless of incidents:
1. What worked in the coordinated release
2. What worked in incident response
3. What we should change for 2027
Even with zero incidents, the retro happens. The lessons
from a smooth release are as valuable as the lessons from
a bad one.
PART 9 — RISK REGISTER
R1 Logistics v4.0 fails for the same reason as last time.
Mitigation: blue-green strategy, instant rollback. Plus
a 4-hour soak in pre-production with synthetic peak load.
R2 Identity MFA opt-in surge floods support.
Mitigation: stage 1 only enables for opt-in merchants;
support briefed; FAQ pre-published.
R3 Payments retry policy creates duplicate transactions
in edge case.
Mitigation: idempotency key enforced at API layer;
canary watches duplicate-charge metric specifically.
R4 All three teams "Go" at T-7 but one slips at T-1.
Mitigation: explicit policy that releases CAN ship
independently; releases NOT inter-dependent by design.
A late Logistics does not block Payments.
R5 On-call burnout pre-BF.
Mitigation: no SRE on-call for non-BF work the week
of release; backup roster doubled for BF week.
PART 10 — SUCCESS CRITERIA
- All three releases at 100% by 2026-11-19 EOD
- Zero customer-visible incidents during BF/CM (11-27 to 12-02)
- Payment false-decline rate measurably reduced
- Carrier-rate p99 measurably reduced
- MFA enrollment available to all merchants
- No emergency security patches during freeze
- Cross-team retro yields >=3 actionable improvements for 2027Why this works
- One shared exit-criteria checklist. Three teams, three releases, one checklist. This is what prevents "we cleared it for our team" failure modes that doom coordinated releases.
- Deployment strategy chosen by maturity, not by preference. Logistics is at Level 2 and the change is high-risk — blue-green is the only acceptable strategy. Payments and Identity are at Level 3 with lower risk — canary is appropriate. The skill's maturity-to-strategy mapping is doing the work.
- Releases independent by design. Risk register R4 is the most important entry: the three releases are deliberately not interlocked. If Logistics slips, Payments and Identity still ship. Tightly-coupled releases are how multi-team programs fail.
- Severity elevation during BF/CM. Reclassifying P1 to P0, P2 to P1, P3 to P2 for the BF window is the operational discipline that distinguishes a delivery manager from a project manager. The same severity rubric does not work across all calendar moments.
- Rollback dry-runs at T-14, not T-1. Dry-runs at T-1 always reveal a step you forgot to test. Done at T-14 there is still time to fix the rollback procedure itself.
- Mandatory post-mortem even with zero incidents. Most teams only run a post-mortem after a bad release. The lessons from a smooth release are how you make the next release smoother.
- VP Eng has a written "slip > bad ship" directive. This is the political cover for the on-call EM who has to make a No-Go call at T-1. Without it, the call becomes career-risky.
What's next
- The post-release retros at T+14 use `../sprint-retrospective/` for the structure.
- Any incidents that occur use `../execution/post-mortem/` for blameless RCA.
- Customer-facing communications use `../execution/release-notes/` and `../execution/launch-playbook/`.
- Feature flag strategy details for Payments and Identity are anchored in `../execution/feature-flag-strategy/`.
- For Logistics' next release after Black Friday, escalate to `../agile-coach/` to bring the team's maturity from Level 2 to Level 3.
- Cross-team dependency tracking pre-release uses `../execution/dependency-map/`.
Deployment Patterns: Blue-Green, Canary, Rolling
Read this when selecting a deployment strategy and defining its rollback path and canary success thresholds. Moved verbatim from SKILL.md.
Select Deployment Strategy
| Strategy | When to Use | Rollback Speed | Risk Level |
|---|---|---|---|
| Blue-Green | Need instant rollback, have 2x infrastructure | Instant (switch traffic) | Low |
| Canary | Want to validate with subset of users first | Fast (stop traffic shift) | Low-Medium |
| Rolling | Cost-constrained, can tolerate mixed versions | Moderate (re-deploy old) | Medium |
| Big Bang | Small app, low traffic, maintenance window OK | Slow (full redeploy) | High |
Blue-Green deployment:
Load Balancer -> [BLUE v2.4 - Active] | [GREEN v2.5 - Staging]
SWITCH: Route traffic Blue -> Green
ROLLBACK: Route traffic Green -> Blue (instant)Canary deployment progression:
Stage 1: 95% old / 5% new -- Monitor for 30 min
Stage 2: 75% old / 25% new -- Monitor for 1 hour
Stage 3: 50% old / 50% new -- Monitor for 2 hours
Stage 4: 0% old / 100% new -- Full rolloutValidation checkpoint: At each canary stage, check error rate (<1%), latency P99 (<threshold), and health checks. Any breach halts progression and triggers rollback.
Incident Management: Severity, Response & Post-Mortem
Read this when triaging or coordinating a production incident, or defining the severity and response-time policy. Moved verbatim from SKILL.md.
Manage Incidents
The agent follows the DETECT -> TRIAGE -> RESPOND -> RESOLVE -> REVIEW process:
Severity levels:
| Severity | Criteria | Response Time | Resolution Target |
|---|---|---|---|
| SEV-1 | Complete outage or data loss | 15 minutes | 4 hours |
| SEV-2 | Major feature unavailable | 30 minutes | 8 hours |
| SEV-3 | Minor feature impact, workaround available | 2 hours | 24 hours |
| SEV-4 | Cosmetic, no customer impact | 8 hours | 5 days |
Incident workflow: 1. Detect -- Alert fires, monitoring triggers, user reports 2. Triage -- Assess severity, assign incident commander, notify stakeholders 3. Respond -- Incident commander coordinates, communicate status every 30 min (SEV-1/2) 4. Resolve -- Deploy fix, verify restoration, confirm with monitoring 5. Review -- Post-mortem within 48 hours, document timeline, root cause, action items
Validation checkpoint: Every SEV-1/SEV-2 incident must produce a post-mortem with action items, owners, and due dates.
Red Flags: Delivery Manager
Common ways this skill's output goes wrong — concrete examples, why they're bad, and how to fix them. Pair with the SKILL.md and Troubleshooting table.
How to use this document
When you have just produced a release plan, incident response, change-request evaluation, or maturity assessment, scan the red flags below. Each red flag shows a bad and good version.
---
Red Flag 1: Blame-Seeking Incident Handling
Symptom. Post-incident review focuses on "who did this" — naming individuals, assigning fault. Quiet rooms, defensive language, no candid contributions.
Why it's bad. Blame culture destroys reporting. Engineers stop flagging near-misses; small problems compound into outages. Allspaw's blameless post-mortem framing exists because the alternative empirically reduces safety. Naming a culprit is satisfying and counter-productive.
Bad example:
Post-incident: "Raj deployed without proper review. Action: written warning. Lessons: be more careful."
Good example:
Post-incident: "The deployment passed our review gate but our review gate did not catch the missing config flag. Root cause: review checklist did not include config-flag verification for canary deploys. Action: update checklist + add automated check. Raj's deploy followed our process; the process needs work."
How to catch it. Read the post-mortem. Does it name an individual as the cause? If yes, the framing is unsafe.
---
Red Flag 2: Missing Rollback Rehearsal
Symptom. Release plan documents a rollback procedure, but the procedure has never been tested in production-like conditions.
Why it's bad. Untested rollback procedures fail when needed. The 3am incident is not the time to discover that the rollback script depends on a tool no one has installed, or that the database migration is not reversible. Maturity Level 4-5 requires rehearsed rollback.
Bad example:
Release plan: "Rollback: revert deploy via Jenkins. DB migration is forward-only; data recovery via backup if needed."
Good example:
Release plan: "Rollback procedure tested in staging on 2026-05-15 (signed off by EM + on-call). Migration designed as expand-contract: new columns added in week 1, code switches to new columns in week 2, old columns removed in week 3 — fully rollback-safe at each step. Rollback target time: 15 min p50, 30 min p95."
How to catch it. Has the rollback been rehearsed in the last 90 days, with measured target time? If not, the plan is theoretical.
---
Red Flag 3: Error Budget Treated as Reliability Theater
Symptom. Team has SLOs and an "error budget" but never actually slows feature work when the budget is burned.
Why it's bad. The point of error budgets is to create an automatic tension between reliability and feature velocity. Budgets that never bite are decorative. Maturity Level 4-5 organizations enforce budget consequences: when burned, feature freeze until reliability work restores it.
Bad example:
SLO: 99.9% uptime. Budget for the month: 43 min. Actual downtime: 4 hours. Action: noted in monthly report, continued feature work."
Good example:
SLO: 99.9% uptime. Budget: 43 min/month. Actual: 4 hours (budget exceeded by 5x). Action triggered by policy: feature work paused, 100% of capacity to reliability for 2 weeks. Restoration plan: 3 named items, ETA documented. Restart criteria: budget restored to <50% consumption for 30 days."
How to catch it. Has your team ever paused feature work because the error budget was burned? If never, the budget is decorative.
---
Red Flag 4: Deployment Strategy Mismatch
Symptom. Team uses blue-green deployment for a high-traffic, stateful service where canary would surface bugs earlier. Or rolling deployment for a service where blast-radius needs full isolation.
Why it's bad. Each strategy has a profile: blue-green = fast switch, double infrastructure cost, hard for stateful; canary = gradual exposure, slow validation, requires monitoring sophistication; rolling = simple, partial exposure during rollout. Mismatched strategy produces either (a) bigger blast radius than necessary or (b) unnecessary cost.
Bad example:
"We use blue-green for everything." (One service has 200 GB of stateful in-memory cache; blue-green requires warming the green environment for 90 min before switch.)
Good example:
"Deployment strategy per service: stateless APIs use rolling (simple, fast). Customer-facing UI uses canary (5% -> 25% -> 100% over 4 hours, with auto-rollback on error-rate spike). Stateful cache service uses blue-green with pre-warming. Documented per-service in runbook."
How to catch it. Can you justify the deployment strategy per service? If not, you are using one strategy for everything.
---
Red Flag 5: Communication Plan Missing T-7/T-1/T+1
Symptom. Release plan covers T-0 (the deploy itself) but no pre-deploy comms, no go/no-go gate, no post-deploy follow-up.
Why it's bad. Surprises break trust with stakeholders. A release that ships without T-7 scope-finalization and T-1 go/no-go feels chaotic to support, sales, and customer-facing teams. A release without T+1 follow-up leaves customers and stakeholders wondering whether it landed safely.
Bad example:
Release plan: "Deploy v2.5.0 on Tuesday at 10am. Slack post when done."
Good example:
Release plan: "T-7 (Tue prior): scope frozen, release notes drafted, internal preview posted. T-1 (Mon): go/no-go meeting at 4pm with eng, product, support, marketing. Owner has authority to delay. T-0 (Tue 10am): deploy, monitoring on, status updates every 30 min in #release. T+1 (Wed): customer comms (changelog, release email if customer-facing), retro scheduled for following week."
How to catch it. Does the plan cover all four checkpoints? Missing any is a process gap.
---
Red Flag 6: Change Advisory Board (CAB) as Rubber Stamp
Symptom. CAB meets weekly, approves every change request in <2 minutes per request, never blocks or modifies a change. Or, CAB blocks every change, becoming a velocity tax.
Why it's bad. Both ends are anti-patterns. A rubber-stamp CAB is bureaucratic theater — it adds delay without adding safety. A blocking CAB is risk-averse paranoia — it slows the org without proportionate risk reduction. Healthy CABs are exceptions-based: standard changes auto-approve, only high-risk changes need real review.
Bad example:
CAB approves 100% of 47 requests this month, average 90 seconds per request.
Good example:
Change taxonomy: Standard (pre-approved, automated, no CAB) = 80% of changes. Normal (CAB review) = 18%. Major (executive review + customer comm) = 2%. CAB only sees 'Normal' and 'Major' — about 10 requests per month, each with a real review. Standard changes flow through CI/CD."
How to catch it. What % of changes does CAB see? If above 50%, the taxonomy is broken. If 100% approved, the review is fake.
---
Red Flag 7: Incident Severity Inflation or Deflation
Symptom. Every minor issue gets logged as Sev-1 (inflation), or genuine outages stay at Sev-3 (deflation) because higher severity triggers paperwork.
Why it's bad. Severity inflation desensitizes the team — "another Sev-1, ignore the page." Severity deflation hides real problems — customers experience outages while the dashboard says "green." Both produce wrong investment in reliability.
Bad example:
Last 30 days: 42 Sev-1 incidents declared. 38 were minor support tickets escalated by frustrated users.
Good example:
Severity rubric documented: Sev-1 = >5% of customers impacted, revenue impact, or data loss. Sev-2 = degradation affecting >1% customers. Sev-3 = isolated. Quarterly severity review by senior on-call to recalibrate. Sev-1 rate stable at 1-3 per month."
How to catch it. Sample 10 recent Sev-1 declarations. How many actually meet the documented criteria? Below 80% match means severity is misused.
---
Red Flag 8: Runbook That No One Has Run Recently
Symptom. Runbook for database failover, dated 2022, never tested. When the failover is needed, half the commands fail because the tool changed.
Why it's bad. Runbooks rot faster than code. A runbook untested in 6+ months should be treated as fiction. The fix is game-day exercises — scheduled runbook executions on staging or production with safety net.
Bad example:
"We have a comprehensive runbook for database failover." (Last executed 2022. Tools referenced are deprecated.)
Good example:
"Quarterly game-day: rotation of critical runbooks tested by on-call engineer in staging or controlled production. Last database-failover game-day: 2026-04-10, all steps executed, 3 commands updated, runtime measured (12 min vs 18 min target). Runbook freshness tracked per item."
How to catch it. For your top 5 critical runbooks, when were they last executed end-to-end? If any over 6 months, that runbook is suspect.
---
Red Flag 9: Feature Flags Used Without Cleanup
Symptom. Codebase has 400+ feature flags, half of them set to 100% on for 2+ years. Conditional logic everywhere, nobody knows which flags are still meaningful.
Why it's bad. Feature flag debt is real debt. Every flag is conditional complexity, a potential bug surface, and a cognitive tax on engineers. The discipline is flag-with-end-date.
Bad example:
Feature flag inventory: 412 flags. 187 at 100% on for >18 months. 23 at 0% with no documentation on why.
Good example:
Flag policy: every flag has an owner, a creation date, and a target sunset date. Monthly flag-cleanup ritual: flags past sunset date either removed or re-justified. Current inventory: 41 flags, all under 6 months old or actively managed."
How to catch it. How many flags are over 12 months old? If above 20, you have flag debt.
---
Red Flag 10: Deploy Frequency Without Lead Time
Symptom. Team reports "we deploy 50 times per week" but lead time from commit to production is 8 days.
Why it's bad. Deploy frequency without lead time hides the real bottleneck. DORA's four metrics work together: deploy frequency, lead time, change failure rate, MTTR. Reporting one without the others paints a misleading picture.
Bad example:
Quarterly delivery report: "Deployments: 287 (industry-leading). Reliability: high."
Good example:
Quarterly delivery report (DORA): Deploys per week = 50, lead time p50 = 8 days (target 3), change failure rate = 12% (target <15%), MTTR = 42 min (target <60). Improvement area: lead time — root cause is review queue depth, action plan in place."
How to catch it. Does your delivery report show all four DORA metrics? If not, one or more is being hidden.
---
Red Flag 11: SLA Promises Without Capacity to Meet Them
Symptom. Sales promises 99.99% uptime in customer contracts. Engineering has not staffed for that SLO; actual uptime is 99.5%.
Why it's bad. Promised reliability without engineering capacity produces breached contracts, SLA credits, and customer churn. SLOs must be co-owned by sales and engineering, with cost implications visible to both.
Bad example:
"We promise 99.99% in enterprise contracts." (Engineering team of 5 supporting one region, no 24/7 on-call, last quarter uptime 99.5%.)
Good example:
"SLO tiers: 99.9% standard (covered by current capacity), 99.95% premium (requires multi-region, costs $X/month, dedicated on-call rotation), 99.99% enterprise (requires both + active-active, costs $Y, contract minimums). Sales authorized to promise tier matching customer commitment."
How to catch it. Are your contractual SLAs aligned with your engineering capacity? If not, you are pre-paying penalties.
---
Red Flag 12: Maturity Score Inflation
Symptom. Team self-assesses at Level 4 (Continuous Deployment) but actual deploys are manual, monitoring is uptime-only, and rollback is not automated.
Why it's bad. Inflated maturity assessments hide real gaps. Leadership invests based on the inflated number ("we're already great at delivery, invest elsewhere") while real risks accumulate. The SKILL.md's level criteria exist precisely to prevent this.
Bad example:
"Self-assessment: Level 4. We deploy a lot." (No automation, no canary, no auto-rollback, basic uptime monitoring.)
Good example:
"Self-assessment: Level 2 (Automated Build/Test). Evidence: CI passing, automated unit tests, manual deploys via Jenkins, basic uptime monitoring. Target Level 3 by Q4: deploy automation + comprehensive monitoring. Investment plan: $X, 2 engineers for 1 quarter."
How to catch it. For each level claim, name the specific evidence required by the SKILL.md's level criteria. If evidence is missing, downgrade the level.
---
Red Flag Quick Reference
| # | Anti-pattern | One-line check |
|---|---|---|
| 1 | Blame-Seeking Incident Handling | Post-mortem names individuals as cause? |
| 2 | Untested Rollback | Rollback rehearsed in last 90 days? |
| 3 | Error Budget Theater | Has feature work paused when budget burned? |
| 4 | Deployment Strategy Mismatch | Per-service strategy justified? |
| 5 | Missing T-7/T-1/T+1 | All four release checkpoints in plan? |
| 6 | CAB Rubber Stamp / Blocker | <50% of changes go to CAB, real review when they do? |
| 7 | Severity Inflation/Deflation | 80%+ of declared severities match rubric? |
| 8 | Stale Runbook | Last end-to-end execution under 6 months? |
| 9 | Feature Flag Debt | Flags over 12 months under 20 total? |
| 10 | Deploy Frequency Without Lead Time | All 4 DORA metrics reported together? |
| 11 | SLA Beyond Capacity | Contractual SLA aligned with engineering capacity? |
| 12 | Maturity Score Inflation | Each level claim has specific evidence? |
Related Reading
- SKILL.md Troubleshooting section (for symptom -> root cause -> resolution)
- references/release-checklist.md (if present)
- references/incident-response.md (if present)
- agile-coach/references/red-flags.md (for adjacent maturity-assessment patterns)
Release Process: Maturity, Planning, Change Management & DORA
Read this when assessing delivery maturity, building a release plan and exit criteria, evaluating change requests, or interpreting DORA metrics. Also contains the release-readiness worked example, the cross-skill integration map, the troubleshooting matrix, and success criteria — all moved verbatim from SKILL.md.
1. Assess Delivery Maturity
The agent evaluates the team's delivery pipeline against 5 maturity levels:
| Level | Name | Characteristics |
|---|---|---|
| 1 | Manual Delivery | Manual builds, manual testing, manual deploys, reactive monitoring |
| 2 | Automated Build/Test | CI pipeline, automated unit tests, manual deploys, basic monitoring |
| 3 | Continuous Delivery | Full CI/CD, automated testing, push-button deploys, comprehensive monitoring |
| 4 | Continuous Deployment | Automated deploys, feature flags, canary releases, self-healing systems |
| 5 | DevOps Excellence | Zero-downtime deploys, automated rollbacks, chaos engineering, full observability |
Validation checkpoint: Identify current level and target level. Focus improvement efforts on one level at a time.
2. Plan Release
The agent creates a release plan covering:
1. Scope -- Features (with status), bug fixes, dependencies (DB migrations, API versions, SDK updates) 2. Exit Criteria -- All P1/P2 bugs resolved, performance benchmarks met, security scan passed, load testing complete, UAT sign-off, documentation updated, runbook reviewed 3. Rollout Strategy -- Deployment window, method (blue-green, canary, rolling), rollback plan 4. Communication Plan -- T-7 (scope finalized), T-1 (go/no-go), T-0 (release notes), T+1 (customer notification)
python scripts/release_checker.py --version v2.5.0Validation checkpoint: Go/No-Go decision requires all exit criteria met. Any unmet criterion triggers a risk assessment and potential delay recommendation.
3. Evaluate Change Requests
| Change Type | Approval Required | Lead Time |
|---|---|---|
| Standard | None (pre-approved, low risk) | 0 |
| Normal | CAB (Change Advisory Board) | 5 days |
| Expedited | Manager approval | 24 hours |
| Emergency | On-call approval | 0 |
Each change request requires: description, justification, impact analysis (systems, services, users, downtime), implementation plan, rollback plan, testing plan, and scheduled window.
Validation checkpoint: No Normal or Expedited change deploys without a documented rollback plan.
Example: Release Readiness Check
$ python scripts/release_checker.py --version v2.5.0
Release Readiness: v2.5.0
=========================
Type: Minor Release (new features)
Target Date: January 25, 2024
Exit Criteria:
[PASS] All P1/P2 bugs resolved (0 open)
[PASS] Performance benchmarks met (P99: 320ms < 500ms target)
[PASS] Security scan passed (0 critical, 0 high)
[PASS] Load testing complete (sustained 2x peak traffic)
[PASS] UAT sign-off received (Jan 23)
[WARN] Documentation: 2 pages pending review
[PASS] Runbook reviewed and updated
Recommendation: CONDITIONAL GO
- Complete documentation review before T-0
- Deployment strategy: Blue-green (recommended for this release size)
- Rollback plan: Instant switch to blue environment
- Monitoring period: 24 hours post-deployDORA Metrics
| Metric | Definition | Elite Target |
|---|---|---|
| Deployment Frequency | Deploys per day/week | Multiple per day |
| Lead Time for Changes | Commit to production | <1 hour |
| Change Failure Rate | Failed deployments % | <5% |
| MTTR | Mean time to recovery | <1 hour |
python scripts/deploy.py --env production --strategy canaryCross-Skill Integration
| Activity | Primary Skill | Delivery Manager Contribution |
|---|---|---|
| Release notes | execution/release-notes/ | Provides ticket list, timeline, deployment details |
| Stakeholder notification | senior-pm/ | Aligns communication plan with release calendar |
| Sprint demo coordination | scrum-master/ | Confirms demo-ready state matches release scope |
| Launch risk assessment | discovery/pre-mortem/ | Supplies deployment risk data for Tiger classification |
Troubleshooting
| Problem | Likely Cause | Resolution |
|---|---|---|
| Canary deployment shows elevated errors but feature works in staging | Environment parity gap -- staging lacks production data volume, traffic patterns, or third-party integrations | Improve staging fidelity; use traffic shadowing before canary; define canary success thresholds based on production baselines, not staging |
| Release go/no-go keeps getting deferred | Exit criteria too rigid or too many items flagged as blockers at the last moment | Separate "must-have" from "nice-to-have" criteria upfront; run readiness checks at T-7 and T-3 to surface issues early |
| Incident post-mortems produce action items that never get implemented | Actions lack owners, due dates, or priority relative to feature work | Assign every action to a named owner with a calendar date; reserve sprint capacity for reliability work; track post-mortem actions in a dedicated Jira board |
| Error budget burns through in the first week of the month | Single large incident or multiple small incidents compounding | Implement burn-rate alerting at 50% and 75% thresholds; auto-freeze non-critical deployments when burn rate exceeds 1.5x |
| Change requests bypass the CAB process | Emergency change pathway overused; teams lack awareness of change types | Audit emergency changes monthly; retrain teams on change classification; add automation to flag changes missing required approvals |
| DORA metrics stagnate despite tooling investment | Measuring deployment frequency without addressing batch size, or measuring MTTR without improving observability | Focus on leading indicators (batch size, test coverage, observability depth) before expecting DORA improvement |
| Rollback takes longer than expected | Rollback plan not tested; database migrations are not backward-compatible | Require rollback rehearsal for every major release; enforce backward-compatible migration policy; blue-green with instant switch as default strategy |
Success Criteria
- Change failure rate stays below 5% measured over a rolling 30-day window
- Mean time to recovery (MTTR) for SEV-1/SEV-2 incidents is under 1 hour
- 100% of SEV-1/SEV-2 incidents produce a post-mortem with action items within 48 hours
- Error budget consumption stays below 80% in any given month
- Release cadence meets or exceeds the target deployment frequency (weekly or better)
- Zero deployments proceed without a documented rollback plan
- DORA metrics show quarter-over-quarter improvement across all four measures
SLA & Error Budget Management
Read this when calculating SLA compliance, error budgets, and burn rates, or setting deployment-freeze thresholds. Moved verbatim from SKILL.md.
Track SLA and Error Budget
python scripts/sla_calculator.py --service portal --period monthError budget calculation example:
SLA: 99.9% availability
Error Budget: 0.1% = 43.8 minutes/month
Budget Consumption:
Incident 1: 15 min
Incident 2: 5 min
Maintenance: 0 min (scheduled, excluded)
Total used: 20 min
Remaining: 23.8 min (54% remaining)
Burn rate: 0.8x (on track)Validation checkpoint: If error budget burn rate exceeds 1.5x, freeze non-critical deployments until burn rate normalizes.
#!/usr/bin/env python3
"""Delivery Metrics Tracker - Track DORA metrics and delivery health over time.
Reads deployment and incident data, calculates the four DORA metrics, and
classifies the team against industry benchmarks (Elite/High/Medium/Low).
Usage:
python delivery_metrics_tracker.py --data delivery.json
python delivery_metrics_tracker.py --data delivery.json --period 30 --json
python delivery_metrics_tracker.py --example
"""
import argparse
import json
import sys
from datetime import datetime, timedelta
DORA_BENCHMARKS = {
"deployment_frequency": {
"elite": {"label": "Multiple per day", "threshold_per_week": 5},
"high": {"label": "Weekly to daily", "threshold_per_week": 1},
"medium": {"label": "Monthly to weekly", "threshold_per_week": 0.25},
"low": {"label": "Less than monthly", "threshold_per_week": 0},
},
"lead_time_hours": {
"elite": {"label": "Less than 1 hour", "threshold": 1},
"high": {"label": "1 hour to 1 day", "threshold": 24},
"medium": {"label": "1 day to 1 week", "threshold": 168},
"low": {"label": "More than 1 week", "threshold": float("inf")},
},
"change_failure_rate_pct": {
"elite": {"label": "0-5%", "threshold": 5},
"high": {"label": "5-10%", "threshold": 10},
"medium": {"label": "10-15%", "threshold": 15},
"low": {"label": "15%+", "threshold": 100},
},
"mttr_hours": {
"elite": {"label": "Less than 1 hour", "threshold": 1},
"high": {"label": "1-4 hours", "threshold": 4},
"medium": {"label": "4-24 hours", "threshold": 24},
"low": {"label": "More than 1 day", "threshold": float("inf")},
},
}
def load_data(path: str) -> dict:
"""Load delivery data from JSON file."""
with open(path, "r") as f:
return json.load(f)
def parse_dt(s: str) -> datetime:
"""Parse datetime string."""
for fmt in ("%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S", "%Y-%m-%d"):
try:
return datetime.strptime(s, fmt)
except ValueError:
continue
raise ValueError(f"Cannot parse: {s}")
def classify(metric_name: str, value: float) -> str:
"""Classify a metric value against DORA benchmarks."""
benchmarks = DORA_BENCHMARKS[metric_name]
if metric_name == "deployment_frequency":
if value >= benchmarks["elite"]["threshold_per_week"]:
return "Elite"
elif value >= benchmarks["high"]["threshold_per_week"]:
return "High"
elif value >= benchmarks["medium"]["threshold_per_week"]:
return "Medium"
return "Low"
else:
if value <= benchmarks["elite"]["threshold"]:
return "Elite"
elif value <= benchmarks["high"]["threshold"]:
return "High"
elif value <= benchmarks["medium"]["threshold"]:
return "Medium"
return "Low"
def analyze_delivery(data: dict, period_days: int = 30) -> dict:
"""Calculate DORA metrics from delivery data."""
service = data.get("service", "Unknown")
deployments = data.get("deployments", [])
incidents = data.get("incidents", [])
now = datetime.now()
cutoff = now - timedelta(days=period_days)
# Filter to period
period_deployments = []
for d in deployments:
try:
dt = parse_dt(d["date"])
if dt >= cutoff:
period_deployments.append(d)
except (ValueError, KeyError):
pass
period_incidents = []
for inc in incidents:
try:
dt = parse_dt(inc["detected"])
if dt >= cutoff:
period_incidents.append(inc)
except (ValueError, KeyError):
pass
# 1. Deployment Frequency
deploy_count = len(period_deployments)
weeks = period_days / 7
deploys_per_week = round(deploy_count / weeks, 2) if weeks > 0 else 0
# 2. Lead Time for Changes
lead_times = []
for d in period_deployments:
if "commit_time" in d and "deploy_time" in d:
try:
commit_dt = parse_dt(d["commit_time"])
deploy_dt = parse_dt(d["deploy_time"])
lt_hours = (deploy_dt - commit_dt).total_seconds() / 3600
if lt_hours >= 0:
lead_times.append(round(lt_hours, 1))
except ValueError:
pass
avg_lead_time = round(sum(lead_times) / len(lead_times), 1) if lead_times else 0
median_lead_time = sorted(lead_times)[len(lead_times) // 2] if lead_times else 0
# 3. Change Failure Rate
failed = sum(1 for d in period_deployments if d.get("failed", False) or d.get("rolled_back", False))
cfr = round(failed / deploy_count * 100, 1) if deploy_count > 0 else 0
# 4. Mean Time to Recovery
recovery_times = []
for inc in period_incidents:
if "detected" in inc and "resolved" in inc:
try:
detected = parse_dt(inc["detected"])
resolved = parse_dt(inc["resolved"])
rt_hours = (resolved - detected).total_seconds() / 3600
if rt_hours >= 0:
recovery_times.append(round(rt_hours, 1))
except ValueError:
pass
avg_mttr = round(sum(recovery_times) / len(recovery_times), 1) if recovery_times else 0
# Classifications
metrics = {
"deployment_frequency": {
"value": deploys_per_week,
"unit": "deploys/week",
"total_in_period": deploy_count,
"classification": classify("deployment_frequency", deploys_per_week),
},
"lead_time": {
"value": avg_lead_time,
"median": median_lead_time,
"unit": "hours",
"sample_size": len(lead_times),
"classification": classify("lead_time_hours", avg_lead_time),
},
"change_failure_rate": {
"value": cfr,
"unit": "%",
"failed_deploys": failed,
"total_deploys": deploy_count,
"classification": classify("change_failure_rate_pct", cfr),
},
"mttr": {
"value": avg_mttr,
"unit": "hours",
"incidents_in_period": len(period_incidents),
"sample_size": len(recovery_times),
"classification": classify("mttr_hours", avg_mttr),
},
}
# Overall classification
classifications = [m["classification"] for m in metrics.values()]
class_scores = {"Elite": 4, "High": 3, "Medium": 2, "Low": 1}
avg_class = sum(class_scores.get(c, 1) for c in classifications) / len(classifications)
if avg_class >= 3.5:
overall = "Elite"
elif avg_class >= 2.5:
overall = "High"
elif avg_class >= 1.5:
overall = "Medium"
else:
overall = "Low"
# Recommendations
recs = []
for name, m in metrics.items():
if m["classification"] in ("Low", "Medium"):
if name == "deployment_frequency":
recs.append("Increase deployment frequency by reducing batch size and automating the release pipeline.")
elif name == "lead_time":
recs.append("Reduce lead time by improving CI/CD pipeline speed, automating testing, and reducing approval gates.")
elif name == "change_failure_rate":
recs.append("Lower change failure rate by improving test coverage, adding canary deployments, and enhancing code review practices.")
elif name == "mttr":
recs.append("Improve MTTR by investing in observability (logging, tracing, alerting) and pre-defined runbooks.")
return {
"service": service,
"period_days": period_days,
"overall_classification": overall,
"metrics": metrics,
"recommendations": recs,
}
def print_report(result: dict) -> None:
"""Print human-readable DORA metrics report."""
print(f"\nDORA Metrics Report: {result['service']}")
print(f"Period: Last {result['period_days']} days")
print("=" * 60)
print(f"Overall Classification: {result['overall_classification']}")
print()
m = result["metrics"]
df = m["deployment_frequency"]
print(f"Deployment Frequency: {df['value']} {df['unit']} ({df['total_in_period']} total)")
print(f" Classification: {df['classification']}")
lt = m["lead_time"]
print(f"Lead Time for Changes: {lt['value']}h avg, {lt['median']}h median (n={lt['sample_size']})")
print(f" Classification: {lt['classification']}")
cfr = m["change_failure_rate"]
print(f"Change Failure Rate: {cfr['value']}% ({cfr['failed_deploys']}/{cfr['total_deploys']} failed)")
print(f" Classification: {cfr['classification']}")
mttr = m["mttr"]
print(f"MTTR: {mttr['value']}h avg ({mttr['incidents_in_period']} incidents)")
print(f" Classification: {mttr['classification']}")
if result["recommendations"]:
print(f"\nRecommendations:")
for i, r in enumerate(result["recommendations"], 1):
print(f" {i}. {r}")
print()
def print_example() -> None:
"""Print example delivery data JSON."""
example = {
"service": "payment-api",
"deployments": [
{"date": "2026-03-18", "commit_time": "2026-03-18T09:00:00", "deploy_time": "2026-03-18T11:30:00", "failed": False},
{"date": "2026-03-15", "commit_time": "2026-03-14T14:00:00", "deploy_time": "2026-03-15T10:00:00", "failed": False},
{"date": "2026-03-12", "commit_time": "2026-03-11T16:00:00", "deploy_time": "2026-03-12T09:30:00", "rolled_back": True},
{"date": "2026-03-08", "commit_time": "2026-03-07T10:00:00", "deploy_time": "2026-03-08T14:00:00", "failed": False},
],
"incidents": [
{"id": "INC-001", "severity": "SEV-2", "detected": "2026-03-12T10:00:00", "resolved": "2026-03-12T12:30:00"},
{"id": "INC-002", "severity": "SEV-3", "detected": "2026-03-05T15:00:00", "resolved": "2026-03-05T16:00:00"},
],
}
print(json.dumps(example, indent=2))
def main():
parser = argparse.ArgumentParser(
description="Track DORA metrics and delivery health."
)
parser.add_argument("--data", type=str, help="Path to delivery data JSON file")
parser.add_argument("--period", type=int, default=30, help="Analysis period in days (default: 30)")
parser.add_argument("--json", action="store_true", help="Output results as JSON")
parser.add_argument("--example", action="store_true", help="Print example data JSON and exit")
args = parser.parse_args()
if args.example:
print_example()
return
if not args.data:
parser.error("--data is required (use --example to see the expected format)")
data = load_data(args.data)
result = analyze_delivery(data, args.period)
if args.json:
print(json.dumps(result, indent=2))
else:
print_report(result)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Dependency Mapper - Map and analyze cross-team/cross-service dependencies.
Reads dependency data and produces a dependency matrix, critical path analysis,
and risk assessment for delivery coordination.
Usage:
python dependency_mapper.py --deps dependencies.json
python dependency_mapper.py --deps dependencies.json --json
python dependency_mapper.py --example
"""
import argparse
import json
import sys
from collections import defaultdict
def load_data(path: str) -> dict:
"""Load dependency data from JSON file."""
with open(path, "r") as f:
return json.load(f)
def build_graph(dependencies: list) -> tuple:
"""Build adjacency list and reverse adjacency list from dependencies."""
graph = defaultdict(list)
reverse_graph = defaultdict(list)
all_nodes = set()
for dep in dependencies:
source = dep.get("from")
target = dep.get("to")
if source and target:
graph[source].append({
"target": target,
"type": dep.get("type", "depends_on"),
"risk": dep.get("risk", "Medium"),
"description": dep.get("description", ""),
"owner": dep.get("owner", "Unassigned"),
})
reverse_graph[target].append(source)
all_nodes.add(source)
all_nodes.add(target)
return graph, reverse_graph, all_nodes
def find_cycles(graph: dict, all_nodes: set) -> list:
"""Detect circular dependencies using DFS."""
cycles = []
visited = set()
rec_stack = set()
path = []
def dfs(node):
visited.add(node)
rec_stack.add(node)
path.append(node)
for edge in graph.get(node, []):
neighbor = edge["target"]
if neighbor not in visited:
dfs(neighbor)
elif neighbor in rec_stack:
# Found a cycle
cycle_start = path.index(neighbor)
cycle = path[cycle_start:] + [neighbor]
cycles.append(cycle)
path.pop()
rec_stack.discard(node)
for node in all_nodes:
if node not in visited:
dfs(node)
return cycles
def topological_sort(graph: dict, all_nodes: set) -> list:
"""Topological sort (Kahn's algorithm). Returns empty if cycle exists."""
in_degree = defaultdict(int)
for node in all_nodes:
if node not in in_degree:
in_degree[node] = 0
for node in graph:
for edge in graph[node]:
in_degree[edge["target"]] += 1
queue = [n for n in all_nodes if in_degree[n] == 0]
result = []
while queue:
queue.sort() # Deterministic ordering
node = queue.pop(0)
result.append(node)
for edge in graph.get(node, []):
target = edge["target"]
in_degree[target] -= 1
if in_degree[target] == 0:
queue.append(target)
return result if len(result) == len(all_nodes) else []
def analyze_dependencies(data: dict) -> dict:
"""Analyze dependencies and produce report."""
project = data.get("project", "Unknown")
dependencies = data.get("dependencies", [])
if not dependencies:
return {"project": project, "error": "No dependencies provided"}
graph, reverse_graph, all_nodes = build_graph(dependencies)
# Dependency matrix
matrix = {}
for source in sorted(all_nodes):
row = {}
for edge in graph.get(source, []):
row[edge["target"]] = edge["type"]
matrix[source] = row
# Fan-in / fan-out analysis
node_metrics = {}
for node in sorted(all_nodes):
fan_out = len(graph.get(node, []))
fan_in = len(reverse_graph.get(node, []))
node_metrics[node] = {
"fan_out": fan_out,
"fan_in": fan_in,
"total_connections": fan_out + fan_in,
"is_bottleneck": fan_in >= 3,
"is_hub": fan_out >= 3,
}
# Cycle detection
cycles = find_cycles(graph, all_nodes)
# Execution order
execution_order = topological_sort(graph, all_nodes)
# Risk analysis
risk_counts = {"High": 0, "Medium": 0, "Low": 0}
high_risk_deps = []
for dep in dependencies:
risk = dep.get("risk", "Medium")
risk_counts[risk] = risk_counts.get(risk, 0) + 1
if risk == "High":
high_risk_deps.append({
"from": dep["from"],
"to": dep["to"],
"description": dep.get("description", ""),
"owner": dep.get("owner", "Unassigned"),
})
# Bottlenecks
bottlenecks = [
{"node": node, "fan_in": metrics["fan_in"], "fan_out": metrics["fan_out"]}
for node, metrics in node_metrics.items()
if metrics["is_bottleneck"]
]
# Recommendations
recs = []
if cycles:
recs.append(f"Circular dependencies detected ({len(cycles)} cycle(s)). Break cycles by introducing interfaces or shared contracts.")
if bottlenecks:
for b in bottlenecks:
recs.append(f"'{b['node']}' is a bottleneck ({b['fan_in']} inbound dependencies). Consider decoupling or adding redundancy.")
if high_risk_deps:
unowned = [d for d in high_risk_deps if d["owner"] == "Unassigned"]
if unowned:
recs.append(f"{len(unowned)} high-risk dependency(ies) without an owner. Assign owners immediately.")
if not recs:
recs.append("Dependency structure looks manageable. Continue monitoring during execution.")
return {
"project": project,
"total_nodes": len(all_nodes),
"total_dependencies": len(dependencies),
"risk_distribution": risk_counts,
"execution_order": execution_order,
"has_cycles": len(cycles) > 0,
"cycles": [" -> ".join(c) for c in cycles],
"bottlenecks": bottlenecks,
"high_risk_dependencies": high_risk_deps,
"node_metrics": node_metrics,
"recommendations": recs,
}
def print_report(result: dict) -> None:
"""Print human-readable dependency report."""
if "error" in result:
print(f"Error: {result['error']}")
return
print(f"\nDependency Map: {result['project']}")
print(f"Components: {result['total_nodes']} | Dependencies: {result['total_dependencies']}")
print("=" * 60)
rd = result["risk_distribution"]
print(f"Risk: High={rd.get('High',0)}, Medium={rd.get('Medium',0)}, Low={rd.get('Low',0)}")
if result["has_cycles"]:
print(f"\n!! CIRCULAR DEPENDENCIES DETECTED:")
for c in result["cycles"]:
print(f" {c}")
if result["execution_order"]:
print(f"\nRecommended Execution Order:")
for i, node in enumerate(result["execution_order"], 1):
metrics = result["node_metrics"].get(node, {})
flags = []
if metrics.get("is_bottleneck"):
flags.append("BOTTLENECK")
if metrics.get("is_hub"):
flags.append("HUB")
flag_str = f" [{', '.join(flags)}]" if flags else ""
print(f" {i}. {node} (in:{metrics.get('fan_in',0)} out:{metrics.get('fan_out',0)}){flag_str}")
if result["high_risk_dependencies"]:
print(f"\nHigh-Risk Dependencies:")
for d in result["high_risk_dependencies"]:
print(f" {d['from']} -> {d['to']}: {d['description']} (Owner: {d['owner']})")
if result["recommendations"]:
print(f"\nRecommendations:")
for i, r in enumerate(result["recommendations"], 1):
print(f" {i}. {r}")
print()
def print_example() -> None:
"""Print example dependency data JSON."""
example = {
"project": "Platform Migration",
"dependencies": [
{"from": "Auth Service", "to": "User Database", "type": "depends_on", "risk": "High", "owner": "Alice", "description": "Auth requires user DB schema migration first"},
{"from": "API Gateway", "to": "Auth Service", "type": "depends_on", "risk": "Medium", "owner": "Bob", "description": "Gateway needs auth endpoints available"},
{"from": "Web App", "to": "API Gateway", "type": "depends_on", "risk": "Low", "owner": "Carol", "description": "Frontend depends on gateway routes"},
{"from": "Mobile App", "to": "API Gateway", "type": "depends_on", "risk": "Low", "owner": "Dave", "description": "Mobile depends on gateway routes"},
{"from": "Analytics", "to": "User Database", "type": "depends_on", "risk": "Medium", "owner": "Unassigned", "description": "Analytics reads from user DB"},
{"from": "Analytics", "to": "API Gateway", "type": "depends_on", "risk": "High", "owner": "Unassigned", "description": "Analytics collects API usage data"},
],
}
print(json.dumps(example, indent=2))
def main():
parser = argparse.ArgumentParser(
description="Map and analyze cross-team/cross-service dependencies."
)
parser.add_argument("--deps", type=str, help="Path to dependencies JSON file")
parser.add_argument("--json", action="store_true", help="Output results as JSON")
parser.add_argument("--example", action="store_true", help="Print example dependencies JSON and exit")
args = parser.parse_args()
if args.example:
print_example()
return
if not args.deps:
parser.error("--deps is required (use --example to see the expected format)")
data = load_data(args.deps)
result = analyze_dependencies(data)
if args.json:
print(json.dumps(result, indent=2))
else:
print_report(result)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Risk Register - Manage and score delivery risks with mitigation tracking.
Reads a risk register and produces a scored, prioritized risk report with
heat map, mitigation status, and trend analysis.
Usage:
python risk_register.py --risks risks.json
python risk_register.py --risks risks.json --json
python risk_register.py --example
"""
import argparse
import json
import sys
from datetime import datetime
SEVERITY_MAP = {
(4, 4): "Critical", (4, 5): "Critical", (5, 4): "Critical", (5, 5): "Critical",
(3, 4): "High", (3, 5): "High", (4, 3): "High", (5, 3): "High",
(3, 3): "High", (4, 2): "High", (5, 2): "High",
(2, 4): "Medium", (2, 5): "Medium", (2, 3): "Medium",
(3, 2): "Medium", (4, 1): "Medium", (5, 1): "Medium",
(1, 4): "Medium", (1, 5): "Medium",
(2, 2): "Low", (3, 1): "Low", (1, 3): "Low",
(1, 1): "Low", (1, 2): "Low", (2, 1): "Low",
}
def load_data(path: str) -> dict:
"""Load risk data from JSON file."""
with open(path, "r") as f:
return json.load(f)
def score_risk(risk: dict) -> dict:
"""Score and classify a single risk."""
probability = risk.get("probability", 1)
impact = risk.get("impact", 1)
probability = max(1, min(5, probability))
impact = max(1, min(5, impact))
score = probability * impact
severity = SEVERITY_MAP.get((probability, impact), "Medium")
mitigation = risk.get("mitigation", {})
mit_status = mitigation.get("status", "Not Started")
mit_owner = mitigation.get("owner", "Unassigned")
mit_actions = mitigation.get("actions", [])
# Residual risk (after mitigation)
if mit_status == "Complete":
residual_prob = max(1, probability - 2)
residual_impact = max(1, impact - 1)
elif mit_status == "In Progress":
residual_prob = max(1, probability - 1)
residual_impact = impact
else:
residual_prob = probability
residual_impact = impact
residual_score = residual_prob * residual_impact
return {
"id": risk.get("id", "RISK-???"),
"title": risk.get("title", "Untitled Risk"),
"category": risk.get("category", "General"),
"probability": probability,
"impact": impact,
"score": score,
"severity": severity,
"residual_score": residual_score,
"mitigation_status": mit_status,
"mitigation_owner": mit_owner,
"mitigation_actions": mit_actions,
"description": risk.get("description", ""),
"trigger": risk.get("trigger", ""),
}
def analyze_risks(data: dict) -> dict:
"""Analyze all risks and produce aggregate report."""
project = data.get("project", "Unknown")
risks = data.get("risks", [])
scored_risks = [score_risk(r) for r in risks]
scored_risks.sort(key=lambda x: x["score"], reverse=True)
# Aggregate stats
severity_counts = {"Critical": 0, "High": 0, "Medium": 0, "Low": 0}
mitigation_counts = {"Complete": 0, "In Progress": 0, "Not Started": 0, "Accepted": 0}
category_counts = {}
for r in scored_risks:
severity_counts[r["severity"]] = severity_counts.get(r["severity"], 0) + 1
mitigation_counts[r["mitigation_status"]] = mitigation_counts.get(r["mitigation_status"], 0) + 1
cat = r["category"]
category_counts[cat] = category_counts.get(cat, 0) + 1
total_exposure = sum(r["score"] for r in scored_risks)
residual_exposure = sum(r["residual_score"] for r in scored_risks)
mitigation_effectiveness = round((1 - residual_exposure / total_exposure) * 100, 1) if total_exposure > 0 else 0
# Overall risk level
if severity_counts.get("Critical", 0) > 0:
overall = "Critical"
elif severity_counts.get("High", 0) > 2:
overall = "High"
elif severity_counts.get("High", 0) > 0:
overall = "Elevated"
else:
overall = "Normal"
# Recommendations
recs = []
unmitigated_critical = [r for r in scored_risks if r["severity"] == "Critical" and r["mitigation_status"] in ("Not Started", "Accepted")]
if unmitigated_critical:
recs.append(f"{len(unmitigated_critical)} critical risk(s) without active mitigation -- escalate to steering committee immediately.")
unassigned = [r for r in scored_risks if r["mitigation_owner"] == "Unassigned" and r["severity"] in ("Critical", "High")]
if unassigned:
recs.append(f"{len(unassigned)} high/critical risk(s) with no mitigation owner -- assign owners within 48 hours.")
if mitigation_effectiveness < 30 and len(scored_risks) > 3:
recs.append("Mitigation effectiveness is low. Review mitigation plans for completeness and execution progress.")
return {
"project": project,
"date": datetime.now().strftime("%Y-%m-%d"),
"total_risks": len(scored_risks),
"overall_risk_level": overall,
"total_exposure": total_exposure,
"residual_exposure": residual_exposure,
"mitigation_effectiveness_pct": mitigation_effectiveness,
"severity_distribution": severity_counts,
"mitigation_status": mitigation_counts,
"category_distribution": category_counts,
"risks": scored_risks,
"recommendations": recs,
}
def print_report(result: dict) -> None:
"""Print human-readable risk register report."""
print(f"\nRisk Register: {result['project']}")
print(f"Date: {result['date']} | Total Risks: {result['total_risks']}")
print("=" * 70)
print(f"Overall Risk Level: {result['overall_risk_level']}")
print(f"Total Exposure: {result['total_exposure']} | Residual: {result['residual_exposure']} | Mitigation Effect: {result['mitigation_effectiveness_pct']:.0f}%")
print()
sd = result["severity_distribution"]
print(f"Severity: Critical={sd.get('Critical',0)}, High={sd.get('High',0)}, Medium={sd.get('Medium',0)}, Low={sd.get('Low',0)}")
print(f"\nRisk Details:")
print(f" {'ID':<12} {'Title':<30} {'P':>2} {'I':>2} {'Score':>5} {'Severity':<10} {'Mitigation':<12} {'Owner'}")
print(f" {'-'*12} {'-'*30} {'-'*2} {'-'*2} {'-'*5} {'-'*10} {'-'*12} {'-'*15}")
for r in result["risks"]:
title = r["title"][:28] + ".." if len(r["title"]) > 30 else r["title"]
print(f" {r['id']:<12} {title:<30} {r['probability']:>2} {r['impact']:>2} {r['score']:>5} {r['severity']:<10} {r['mitigation_status']:<12} {r['mitigation_owner']}")
if result["recommendations"]:
print(f"\nRecommendations:")
for i, rec in enumerate(result["recommendations"], 1):
print(f" {i}. {rec}")
print()
def print_example() -> None:
"""Print example risk register JSON."""
example = {
"project": "Platform Migration",
"risks": [
{
"id": "RISK-001",
"title": "Database migration data loss",
"category": "Technical",
"description": "Complex schema migration may cause data corruption",
"trigger": "Migration script fails during production execution",
"probability": 3,
"impact": 5,
"mitigation": {
"status": "In Progress",
"owner": "Alice Chen",
"actions": ["Run migration on staging with production data copy", "Create rollback script"],
},
},
{
"id": "RISK-002",
"title": "Key engineer leaves during migration",
"category": "Resource",
"description": "Single point of failure on legacy system knowledge",
"trigger": "Resignation notice during critical phase",
"probability": 2,
"impact": 4,
"mitigation": {
"status": "Not Started",
"owner": "Unassigned",
"actions": ["Document legacy system architecture", "Cross-train second engineer"],
},
},
{
"id": "RISK-003",
"title": "Third-party API rate limit changes",
"category": "External",
"description": "Vendor may reduce API limits in next billing cycle",
"trigger": "Vendor announcement or unexpected 429 errors",
"probability": 2,
"impact": 3,
"mitigation": {
"status": "Complete",
"owner": "Bob Martinez",
"actions": ["Implemented request caching", "Added rate limit monitoring"],
},
},
],
}
print(json.dumps(example, indent=2))
def main():
parser = argparse.ArgumentParser(
description="Manage and score delivery risks with mitigation tracking."
)
parser.add_argument("--risks", type=str, help="Path to risk register JSON file")
parser.add_argument("--json", action="store_true", help="Output results as JSON")
parser.add_argument("--example", action="store_true", help="Print example risk register and exit")
args = parser.parse_args()
if args.example:
print_example()
return
if not args.risks:
parser.error("--risks is required (use --example to see the expected format)")
data = load_data(args.risks)
result = analyze_risks(data)
if args.json:
print(json.dumps(result, indent=2))
else:
print_report(result)
if __name__ == "__main__":
main()