Overview

Anyone who has done production operations has probably lived through this scenario: you get woken up by an alert at 3 AM, fight the fire until service is restored, hold a postmortem the next day, list a dozen improvement actions in the meeting, send the minutes to the group chat, and everyone says “got it.” Then what? A month later you dig it up and find maybe two or three items actually got done. The rest are collecting dust in some document. Worse, six months later the same incident happens again. You pull up the historical records during the new postmortem and — surprise — the same improvements were suggested last time. Nobody followed up.

That is not a postmortem. That is going through the motions.

Action Items Tracking solves exactly this problem: turning the improvement checklist produced in postmortem meetings into work items with owners, deadlines, acceptance criteria, and continuous tracking until closure. Put simply, the value of a postmortem is not in the meeting itself, but in the three months that follow — whether those action items were actually executed and executed properly.

The Google SRE Book says something to the effect of: reviewing an incident without action items means the review was wasted. But I think that statement is missing half the point — having action items without tracking them is equally wasteful.

This article covers how to actually do action items tracking. We will start with action item classification and lifecycle, move to tool selection, then cover automated reminders and metrics, and finish with a set of practices you can put into production right away.

What Is an Action Item: From Vague Suggestions to Executable Tasks

An Action Item Is Not a Suggestion

Many people confuse “action items” with “suggestions.” Someone says in the postmortem, “we should test more before deploying.” That is a suggestion, not an action item. An action item must be a specific task that is executable, trackable, and verifiable.

A proper action item answers five questions:

ElementDescriptionBad ExampleGood Example
WhatThe specific action to take“Improve monitoring”“Add timeout circuit breaker for downstream calls in the order service, set timeout to 3 seconds”
WhoA specific person, not a team“The dev team”“Zhang San (order service owner)”
WhenA concrete deadline“As soon as possible”“By 2026-08-15”
How to verifyA checkable completion criteria“Optimized”“order_downstream_timeout_total metric appears in Prometheus, and circuit breaker is verified in load test environment”
PriorityP0/P1/P2 classificationNot labeled“P1: affects all users, must complete within two weeks”

An “action item” missing any of these elements is essentially a blank check. You cannot track a blank check.

Action Item Classification

Based on what they improve and how long they take, action items fall into four categories:

1. Technical Fix

Problems solvable by directly changing code or configuration. Bug fixes, adding circuit breaker logic, adding a monitoring metric. Short execution cycle, typically a few days to two weeks.

Examples:
- Fix N+1 query in order-service (P0, within 2 days)
- Add rate limiting middleware to payment-gateway (P1, within 1 week)
- Switch Redis connection pool from lettuce to jedis with proper timeout config (P2, within 2 weeks)

2. Process Improvement

Does not involve code, but requires changing workflows or standards. Adding a canary verification step to the deployment process, updating on-call runbook steps, adjusting change window policies. These involve cross-team coordination, typically 2-4 weeks.

Examples:
- Modify release process: all P0 changes must pass canary environment verification (P1, within 2 weeks)
- Update on-call handbook with Redis cluster failover steps (P2, within 1 week)
- Create config change approval policy: all production config changes require dual review (P1, within 3 weeks)

3. Architecture Optimization

Requires significant changes or architectural adjustments to fully resolve. Introducing message queues to decouple synchronous calls, splitting a monolith, building multi-region disaster recovery. Long cycle, typically 1-3 months or more, needs to be broken into subtasks.

Examples:
- Change order service from synchronous inventory deduction to async message-driven (P1, split into 5 subtasks, complete within 3 months)
- Multi-datacenter disaster recovery for core transaction chain (P0, split into 12 subtasks, complete within 6 months)

4. Knowledge Documentation

Distilling incident experience into documents, training materials, or automation scripts. Writing runbooks, recording postmortem sharing videos, developing automated inspection scripts.

Examples:
- Write a runbook for Redis cluster split-brain incidents (P2, within 1 week)
- Turn this incident's troubleshooting process into training material for team sharing (P2, within 2 weeks)

Action Item Priority Assessment

Priority should not be a gut call. It needs to be based on incident impact and the improvement’s expected value. I recommend a simple scoring matrix:

DimensionScoreDescription
Incident impact scope1-5All users=5, some users=3, individual users=1
Incident frequency1-5Multiple times per month=5, quarterly=3, first time=1
Fix cost1-5Within 1 day=1, within 1 week=3, over 1 month=5
Prevention benefit1-5Eliminates completely=5, partial mitigation=3, documentation only=1

Total = (Impact scope + Frequency) × Prevention benefit / Fix cost

Score >= 10 means P0, 5-9 means P1, < 5 means P2.

This formula is not gospel, but it forces you to think through multiple dimensions when assigning priority, instead of saying “this seems important, mark it P0.”

Full Lifecycle Management of Action Items

An action item goes through five stages from creation to closure. Each stage has clear inputs, outputs, and owners.

Stage 1: Creation

At the end of the postmortem meeting, every action item must have its five elements confirmed on the spot (what, who, when, verification, priority). On-the-spot confirmation matters — if you fill in details online after the meeting, you lose at least 30% of the information.

In practice, the last 15 minutes of a postmortem meeting should be dedicated to this. The facilitator reads each action item, confirms the owner and deadline, and records it directly into the tracking system.

Key output of creation stage: Each action item has a unique ID, clear owner, deadline, acceptance criteria, and priority.

Stage 2: Execution

The owner executes the action item according to plan. The biggest risk in this stage is not doing it poorly — it is forgetting to do it at all.

Action item execution needs visibility:

  • When created, the item enters “Open” status
  • Owner manually moves it to “In Progress” when work begins
  • Each item gets an automatic reminder 7 days before the deadline
  • Overdue items trigger automatic escalation (notifying the owner’s manager and SRE team lead)

Do not underestimate these reminders. I have seen too many action items that were not skipped because someone did not want to do them — the owner was busy with something else and simply forgot. The cost of automated reminders is nearly zero, but the number of action items they rescue is significant.

Stage 3: Verification

When the owner claims completion, the item cannot be auto-closed. It must pass verification before closure.

There are two types of verification:

Automated verification: For action items with clear technical indicators. For example, “add P99 latency monitoring for service X” — the acceptance criterion is that the metric exists in Prometheus, which can be checked by a script.

Manual verification: For process or documentation items. For example, “update the on-call handbook” requires a designated verifier (usually the SRE team lead or postmortem facilitator) to manually review.

Items that fail verification go back to the execution stage. This is stricter than simply closing, but it prevents the “said it was done, but nothing actually happened” scenario.

Stage 4: Archival

After verification passes, the action item enters archived status. Archive does not mean delete — archived items remain searchable and queryable.

An important step in the archival phase is updating the knowledge base: distilling the execution process and results into the team’s incident knowledge base, so future similar issues can be referenced.

Stage 5: Audit

Periodically (quarterly is recommended), audit the archived action items. The audit answers two questions:

  1. Did this action item actually solve the problem? — Check whether similar incidents have recurred
  2. Was the cost-benefit ratio as expected? — Compare actual cost and results against the initial assessment

Audit results are used to improve action item creation quality. If a category of action items is repeatedly created but consistently ineffective, the improvement direction is wrong, and the root cause needs to be rethought.

Lifecycle State Machine

Organizing the five stages into a state machine:

Open
   ├──→ In Progress
   │         │
   │         ├──→ Pending Verification
   │         │         │
   │         │         ├──→ Done ──→ Archived
   │         │         │
   │         │         └──→ Rejected ──→ In Progress
   │         │
   │         └──→ Cancelled  ← Item no longer needed
   └──→ Overdue ──→ Escalation notification

Every state transition must be logged with a timestamp and the person who made the change. This way you can see the complete flow path of any action item at any point in time.

Tool Selection: Do Not Use Excel, and Do Not Reinvent the Wheel

Why Excel Does Not Work

Many teams still track action items in Excel or Google Sheets. One column for the action, one for the owner, one for the deadline, one for status. It looks clear enough, but the problems pile up:

  • No state transition constraints — anyone can change anything
  • No automated reminders — nobody knows when things are overdue
  • No change history — no way to trace what was modified
  • Multi-person collaboration conflicts — nobody knows which version is current
  • No analytics — completion rate is counted manually

Excel works for one-time records, not for continuous tracking. Action item tracking needs a system with state machines, notifications, history, and analytics.

Tool Comparison

There are plenty of tools that can track action items. Which one to pick depends on your team’s current setup and budget. Do not chase the “perfect action item management system” from day one — use what you already have well first.

ToolAdvantagesDisadvantagesUse Case
JiraFeature-complete, customizable state machines, integrated with dev workflowComplex configuration, high maintenanceMid-to-large teams already on Jira
GitHub IssuesLightweight, free, links to code PRsWeak state management, no built-in analyticsSmall teams, open-source projects
GitLab IssuesSimilar to GitHub, has board viewSimplified state managementTeams using GitLab
PingCode / Feishu ProjectsChinese-made, Chinese-friendly UIEcosystem not as rich as JiraDomestic teams
Custom systemFully customizableHigh dev and maintenance costLarge companies with dedicated tool teams

If your team already has Jira (most likely), no need to introduce a new tool. Jira’s custom workflows can handle action item tracking. Atlassian uses Jira work items to track all postmortem action items to ensure they are completed and approved in their own practice (see Atlassian Incident Management Handbook).

Core configuration:

1. Create Action Item Issue Type

Issue Type: Postmortem Action Item
Custom fields:
  - postmortem-id: Linked postmortem document ID
  - action-type: technical-fix / process-improvement / architecture-optimization / knowledge-documentation
  - verification-method: auto / manual
  - verifier: Verifier
  - actual-completion-date: Actual completion date

2. Configure Workflow State Machine

# Jira Workflow Definition (simplified)
transitions:
  - from: Open
    to: In Progress
    condition: assignee != null
  - from: In Progress
    to: Pending Verification
    condition: true
  - from: Pending Verification
    to: Done
    condition: verifier_approval == true
  - from: Pending Verification
    to: In Progress
    condition: verifier_approval == false
  - from: Open
    to: Cancelled
    condition: role == "SRE Lead"

3. Configure Automation Rules

Jira Automation can implement automated reminders and escalation:

# Reminder 7 days before deadline
rule: pre-deadline-reminder
trigger:
  - schedule: "0 9 * * *"
  - condition: duedate <= now() + 7d AND status != Done
action:
  - send_email:
      to: assignee
      subject: "Action item deadline approaching"
      body: "Action item {{issue.key}} will be due on {{issue.duedate}}, please process it soon"

# Escalation after overdue
rule: overdue-escalation
trigger:
  - schedule: "0 10 * * *"
  - condition: duedate < now() AND status != Done
action:
  - send_email:
      to: [assignee, assignee_manager, sre_lead]
      subject: "Action item overdue"
      body: "Action item {{issue.key}} is {{days_overdue}} days overdue"
  - transition_issue:
      to: Overdue

Lightweight Alternative: GitHub Issues + Labels

Teams without Jira can use GitHub Issues for a lightweight action item tracking system. The core idea is to use Labels for status, Milestones for deadlines, and a structured Issue Body template for action item details.

Action Item Issue Template:

---
postmortem: INC-2026-0721-001
type: technical-fix
priority: P0
assignee: @zhangsan
due-date: 2026-08-04
verifier: @lisi
---

## Action Item Description

Add timeout circuit breaker for downstream calls in the order service, set timeout to 3 seconds.

## Acceptance Criteria

- [ ] order_downstream_timeout_total metric appears in Prometheus
- [ ] Circuit breaker verified in load test environment
- [ ] Code merged to main branch

## Linked Postmortem

- Postmortem document: [INC-2026-0721-001 Postmortem Report](link-to-postmortem)
- Incident time: 2026-07-21 02:30 - 03:15
- Impact: Order service timeout, all users, 45 minutes

Label Design:

status/open          — Open
status/in-progress   — In Progress
status/verification  — Pending Verification
status/done          — Done
status/overdue       — Overdue
status/cancelled     — Cancelled

type/technical       — Technical Fix
type/process         — Process Improvement
type/architecture    — Architecture Optimization
type/knowledge       — Knowledge Documentation

priority/p0          — P0 Urgent
priority/p1          — P1 Important
priority/p2          — P2 Normal

Implementing automated reminders with GitHub Actions is not complicated:

# .github/workflows/action-item-reminder.yml
name: Action Item Reminder
on:
  schedule:
    - cron: "0 1 * * *"  # Every day at 9 AM Beijing time

jobs:
  check-overdue:
    runs-on: ubuntu-latest
    steps:
      - name: Check overdue action items
        uses: actions/github-script@v7
        with:
          script: |
            const issues = await github.rest.issues.listForRepo({
              owner: context.repo.owner,
              repo: context.repo.repo,
              labels: ['postmortem-action-item', 'status/open'],
              state: 'open'
            });
            
            const now = new Date();
            for (const issue of issues.data) {
              const body = issue.body || '';
              const dueMatch = body.match(/due-date:\s*(.+)/);
              if (dueMatch) {
                const dueDate = new Date(dueMatch[1].trim());
                const daysLeft = Math.ceil((dueDate - now) / (1000 * 60 * 60 * 24));
                
                if (daysLeft <= 0) {
                  await github.rest.issues.addLabels({
                    ...context.repo,
                    issue_number: issue.number,
                    labels: ['status/overdue']
                  });
                  await github.rest.issues.createComment({
                    ...context.repo,
                    issue_number: issue.number,
                    body: `Warning: This action item is ${Math.abs(daysLeft)} days overdue. Please process it ASAP.`
                  });
                } else if (daysLeft <= 7) {
                  await github.rest.issues.createComment({
                    ...context.repo,
                    issue_number: issue.number,
                    body: `Reminder: This action item will be due in ${daysLeft} days.`
                  });
                }
              }
            }            

This script checks all open action item issues once a day, reminds 7 days before deadline, and automatically labels and comments on overdue items. Simple, brute-force, but effective.

Automated Verification: Let Scripts Check for You

As mentioned earlier, action item verification comes in two flavors: automated and manual. Automate as much as possible, because the bottleneck of manual verification is the verifier — one person verifying dozens of action items will likely just rubber-stamp them.

Automated Verification Script Design

The core of automated verification is: translate “acceptance criteria” into “executable check scripts.” For example, if the acceptance criterion is “order_downstream_timeout_total metric exists in Prometheus,” the check script queries Prometheus for that metric.

Here is a Python-based automated verification framework:

#!/usr/bin/env python3
"""
Postmortem Action Item Automated Verification Framework
"""

import json
import subprocess
import requests
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from typing import List, Optional, Callable
from enum import Enum

class VerificationResult(Enum):
    PASSED = "passed"
    FAILED = "failed"
    ERROR = "error"

@dataclass
class ActionItem:
    """Action item data model"""
    item_id: str
    title: str
    assignee: str
    due_date: str
    priority: str  # P0 / P1 / P2
    action_type: str  # technical-fix / process / architecture / knowledge
    verification_method: str  # auto / manual
    verification_fn: Optional[Callable] = None
    status: str = "open"
    postmortem_id: str = ""
    
@dataclass 
class VerificationReport:
    """Verification report"""
    item_id: str
    result: VerificationResult
    message: str
    checked_at: str
    details: dict = field(default_factory=dict)

class ActionItemVerifier:
    """Action item automated verifier"""
    
    def __init__(self, prometheus_url: str):
        self.prometheus_url = prometheus_url.rstrip("/")
        self.reports: List[VerificationReport] = []
    
    def check_prometheus_metric(self, metric_name: str) -> bool:
        """Check if a metric exists in Prometheus"""
        try:
            resp = requests.get(
                f"{self.prometheus_url}/api/v1/query",
                params={"query": metric_name},
                timeout=10
            )
            data = resp.json()
            return data.get("status") == "success" and len(data.get("data", {}).get("result", [])) > 0
        except Exception as e:
            print(f"Prometheus check failed: {e}")
            return False
    
    def check_jenkins_job_exists(self, job_name: str) -> bool:
        """Check if a Jenkins job exists"""
        try:
            result = subprocess.run(
                ["jenkins-cli", "list-jobs"],
                capture_output=True, text=True, timeout=10
            )
            return job_name in result.stdout.splitlines()
        except Exception as e:
            print(f"Jenkins check failed: {e}")
            return False
    
    def check_grafana_dashboard(self, dashboard_uid: str) -> bool:
        """Check if a Grafana dashboard exists"""
        try:
            resp = requests.get(
                f"http://grafana.internal/api/dashboards/uid/{dashboard_uid}",
                timeout=10
            )
            return resp.status_code == 200
        except Exception as e:
            print(f"Grafana check failed: {e}")
            return False
    
    def check_github_pr_merged(self, repo: str, pr_number: int) -> bool:
        """Check if a GitHub PR has been merged"""
        try:
            resp = requests.get(
                f"https://api.github.com/repos/{repo}/pulls/{pr_number}",
                timeout=10
            )
            data = resp.json()
            return data.get("merged", False)
        except Exception as e:
            print(f"GitHub PR check failed: {e}")
            return False
    
    def verify(self, item: ActionItem) -> VerificationReport:
        """Execute verification"""
        if item.verification_method != "auto" or item.verification_fn is None:
            return VerificationReport(
                item_id=item.item_id,
                result=VerificationResult.ERROR,
                message="This action item does not support automated verification",
                checked_at=datetime.now().isoformat()
            )
        
        try:
            passed = item.verification_fn()
            return VerificationReport(
                item_id=item.item_id,
                result=VerificationResult.PASSED if passed else VerificationResult.FAILED,
                message="Verification passed" if passed else "Verification failed",
                checked_at=datetime.now().isoformat()
            )
        except Exception as e:
            return VerificationReport(
                item_id=item.item_id,
                result=VerificationResult.ERROR,
                message=f"Verification script error: {e}",
                checked_at=datetime.now().isoformat()
            )
    
    def batch_verify(self, items: List[ActionItem]) -> List[VerificationReport]:
        """Batch verification"""
        reports = []
        for item in items:
            if item.status == "pending-verification":
                report = self.verify(item)
                reports.append(report)
                print(f"[{item.item_id}] {report.result.value}: {report.message}")
        return reports
    
    def generate_summary(self, reports: List[VerificationReport]) -> str:
        """Generate verification summary"""
        total = len(reports)
        passed = sum(1 for r in reports if r.result == VerificationResult.PASSED)
        failed = sum(1 for r in reports if r.result == VerificationResult.FAILED)
        errors = sum(1 for r in reports if r.result == VerificationResult.ERROR)
        
        summary = f"""
=====================================
  Action Item Automated Verification Report
  Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
=====================================
  Total: {total}
  Passed: {passed}
  Failed: {failed}
  Errors: {errors}
  Pass Rate: {(passed/total*100):.1f}% (only auto-verifiable items counted)
=====================================
"""
        for r in reports:
            status_icon = "PASS" if r.result == VerificationResult.PASSED else "FAIL"
            print(f"  [{status_icon}] [{r.item_id}] {r.message}")
        
        return summary


# ============ Usage Example ============

if __name__ == "__main__":
    verifier = ActionItemVerifier(prometheus_url="http://prometheus.internal:9090")
    
    # Define action items (in production, pull from Jira or GitHub Issues)
    items = [
        ActionItem(
            item_id="AI-2026-0721-001",
            title="Add timeout circuit breaker monitoring for order service",
            assignee="zhangsan",
            due_date="2026-08-04",
            priority="P0",
            action_type="technical-fix",
            verification_method="auto",
            verification_fn=lambda: verifier.check_prometheus_metric("order_downstream_timeout_total"),
            status="pending-verification",
            postmortem_id="INC-2026-0721-001"
        ),
        ActionItem(
            item_id="AI-2026-0721-002",
            title="Create Grafana dashboard for order service",
            assignee="lisi",
            due_date="2026-08-11",
            priority="P1",
            action_type="technical-fix",
            verification_method="auto",
            verification_fn=lambda: verifier.check_grafana_dashboard("order-service-dashboard"),
            status="pending-verification",
            postmortem_id="INC-2026-0721-001"
        ),
    ]
    
    # Batch verification
    reports = verifier.batch_verify(items)
    
    # Generate report
    print(verifier.generate_summary(reports))

The design concept: each action item specifies a verification function (verification_fn) at creation time. The function is a closure returning a bool, internally calling specific check logic. During batch verification, all “pending-verification” items are iterated, their respective functions executed, and results aggregated.

In practice, verification functions can cover:

  • Check if a Prometheus metric exists
  • Check if a Grafana dashboard exists
  • Check if a Jenkins job exists
  • Check if a GitHub PR has been merged
  • Check if a runbook document has been created
  • Check if an Alertmanager rule has been configured

What percentage of action items can be auto-verified? Based on experience, about 40-60%. Most technical fixes can be auto-verified; process improvements and knowledge documentation basically need manual verification. But this ratio already significantly reduces the verification burden.

Measuring the Effectiveness of Action Item Tracking

The tracking system is built. How do you know if it works? You need data.

Core Metrics

1. Completion Rate

Completion Rate = Completed Action Items / Total Action Items × 100%

This is the most basic metric. But completion rate alone is not enough — if all completed items are low-priority P2s while all P0s are overdue, a high completion rate is meaningless.

So break completion rate down by priority:

PriorityTarget Completion RateNotes
P0>= 95%Urgent items must be almost all completed
P1>= 85%Important items allow some delays
P2>= 70%Normal items have reasonable room for dropping

2. Mean Time to Close (MTTC)

MTTC = Sum of (close_date - creation_date) for all closed items / Number of closed items

MTTC reflects the average time from creation to closure. Broken down by type:

  • Technical Fix: target MTTC <= 14 days
  • Process Improvement: target MTTC <= 30 days
  • Architecture Optimization: target MTTC <= 90 days
  • Knowledge Documentation: target MTTC <= 14 days

3. Overdue Rate

Overdue Rate = Overdue Action Items / Total Action Items × 100%

Overdue rate directly reflects whether the tracking system is working. If overdue rate stays above 20% long-term, the tracking system is effectively nonexistent.

4. Incident Recurrence Rate

Recurrence Rate = Incidents of the same type within 90 days of postmortem / Total postmortems × 100%

This is the ultimate metric. If the tracking system is effective, recurrence rate should continuously decline. If completion rate is high but recurrence rate does not drop, the action item direction is wrong — either the root cause was not actually found, or the improvements treat symptoms but not causes.

5. Verification Pass Rate

Verification Pass Rate = Verified Action Items / Action Items Submitted for Verification × 100%

If verification pass rate stays below 80% long-term, execution quality is problematic — owners claim completion but do not meet acceptance criteria. This may mean the acceptance criteria are too high, or the execution process lacks effective follow-up.

Metrics Dashboard

Build a Grafana dashboard for action item metrics:

{
  "dashboard": {
    "title": "Action Item Tracking Metrics Dashboard",
    "panels": [
      {
        "title": "Action Item Completion Rate (by Priority)",
        "type": "gauge",
        "targets": [
          {
            "expr": "action_items_completed{priority=\"P0\"} / action_items_total{priority=\"P0\"} * 100"
          }
        ]
      },
      {
        "title": "Action Item MTTC Trend (by Type)",
        "type": "graph",
        "targets": [
          {
            "expr": "avg by (type) (action_item_mttc_seconds{status=\"done\"} / 86400)"
          }
        ]
      },
      {
        "title": "Overdue Action Items Count",
        "type": "stat",
        "targets": [
          {
            "expr": "count(action_items{status=\"overdue\"})"
          }
        ]
      },
      {
        "title": "Incident Recurrence Rate (90-day window)",
        "type": "graph",
        "targets": [
          {
            "expr": "incident_recurrence_rate_90d * 100"
          }
        ]
      }
    ]
  }
}

Where does this data come from? You need to push action item status data to Prometheus. If using Jira, a scheduled script can pull action item status and convert it to Prometheus metrics:

#!/usr/bin/env python3
"""
Pull action item status from Jira and push Prometheus metrics
"""

import requests
from prometheus_client import CollectorRegistry, Gauge, push_to_gateway

JIRA_URL = "https://jira.internal"
JIRA_USER = "metrics-reader"
JIRA_TOKEN = "your-token-here"  # Read from environment variable in production

def fetch_action_items():
    """Pull all action items from Jira"""
    jql = 'project = SRE AND issuetype = "Postmortem Action Item"'
    headers = {"Authorization": f"Bearer {JIRA_TOKEN}"}
    
    items = []
    start_at = 0
    while True:
        resp = requests.get(
            f"{JIRA_URL}/rest/api/2/search",
            params={"jql": jql, "startAt": start_at, "maxResults": 100,
                    "fields": "status,priority,assignee,created,duedate,resolutiondate"},
            headers=headers,
            timeout=30
        )
        data = resp.json()
        items.extend(data.get("issues", []))
        if start_at + 100 >= data.get("total", 0):
            break
        start_at += 100
    
    return items

def push_metrics(items):
    """Push Prometheus metrics"""
    registry = CollectorRegistry()
    
    # Count by status
    status_gauge = Gauge(
        "action_items_by_status", 
        "Action items count by status",
        ["status", "priority"],
        registry=registry
    )
    
    # Count by type
    type_gauge = Gauge(
        "action_items_by_type",
        "Action items count by type", 
        ["type"],
        registry=registry
    )
    
    # MTTC
    from datetime import datetime
    mttc_gauge = Gauge(
        "action_item_mttc_seconds",
        "Mean time to close in seconds",
        ["type"],
        registry=registry
    )
    
    for item in items:
        fields = item["fields"]
        status = fields["status"]["name"].lower().replace(" ", "_")
        priority = fields.get("priority", {}).get("name", "P2")
        
        status_gauge.labels(status=status, priority=priority).inc()
    
    push_to_gateway(
        "pushgateway.internal:9091",
        job="action-item-metrics",
        registry=registry
    )
    print(f"Pushed {len(items)} action item metrics to Prometheus")

if __name__ == "__main__":
    items = fetch_action_items()
    push_metrics(items)

Put this script in cron or a systemd timer to run daily, and the Grafana dashboard will show real-time action item metrics.

Common Pitfalls and Countermeasures

Pitfall 1: Too Many Action Items, Cannot Finish Them All

In the postmortem everyone is enthusiastic, and you list twenty-something action items. A week later you find they are impossible to finish, morale drops, and everything gets abandoned.

Countermeasure: Cap action items per postmortem at 5. If there are more than 5, force priority ranking and only track P0 and P1. P2s go into a backlog without mandatory execution. Action items are about quality of execution, not quantity.

Pitfall 2: Owner Is Listed as “Team” or “Everyone”

“Team” is not a person. An action item assigned to “the team” is assigned to no one. Three months later when you ask “was this done?”, everyone on the team thinks it was someone else’s job.

Countermeasure: The owner must be one specific person. One person can own multiple action items, but each item has exactly one owner. If multi-person collaboration is needed, still designate one primary owner, with others as participants.

Pitfall 3: Vague Acceptance Criteria

Acceptance criteria say “optimize well” or “improve monitoring.” When verification time comes, nobody can define what “well” means.

Countermeasure: Acceptance criteria must be verifiable. If you can write a script, write one. If not, at least specify concrete conditions. For example, “P99 latency panel for order-service is visible in Grafana” is far better than “improve monitoring.”

Pitfall 4: Action Items Mixed with Regular Work

Action items get mixed with everyday bugfixes and feature development on the same board. You cannot tell which are postmortem action items and which are routine work. Action items get buried in daily tasks and naturally nobody tracks them.

Countermeasure: Mark action items with a distinct Issue Type (Jira) or Label (GitHub Issues), and give them their own column on the board. Have a dedicated action item status review in the weekly SRE meeting, instead of mentioning it in passing during sprint planning.

Pitfall 5: Postmortem Culture Turns into Blame Culture

The postmortem becomes a blame session. Action items become punishment evidence — “we said to do this last time, why is it not done? Should we dock your performance?” Next time, people minimize action items and pick only easy ones.

Countermeasure: The core of postmortem culture is “blameless” — focus on the issue, not the person. Action item delays should be tracked and improved, but the response is to analyze “why was it not done” (insufficient resources? wrong priority? technical blockers?), not to punish the owner. Meitu’s SRE team summarized the three golden postmortem questions: How can we recover faster? How can we prevent recurrence? What good practices can we distill and standardize? (see Meitu SRE Postmortem Experience Summary) — the answers to these three questions are where action items come from, not the pursuit of “who made the mistake.”

Pitfall 6: Items Completed but Not Audited — Done in Name Only

Some action items appear complete but the actual effect is questionable. For example, “add monitoring metric” — the metric was added but nobody looks at it, alert thresholds are unreasonable, and it still does not work.

Countermeasure: Add an “effectiveness verification” step in the verification phase. Thirty days after closure, check whether the improvement actually delivered the expected effect. For example, was the added monitoring metric used in subsequent incidents? Was the updated runbook actually referenced? Effectiveness verification does not need to cover every item, but P0 action items must have it.

Team Practice Recommendations

Based on team size, here are three tiers of practice recommendations:

Small Team (1-10 people)

GitHub Issues or Feishu multi-dimensional tables are sufficient. Core practices:

  1. Maximum 5 action items per postmortem
  2. Each with clear owner and deadline
  3. Review action item status in weekly standup
  4. Calculate completion rate at month-end, share in group

No need for complex state machines or automated verification. Lightweight but not lost — the key is having someone watching.

Mid-size Team (10-50 people)

Use Jira with custom workflows. Core practices:

  1. Dedicated Issue Type for action items, separate board column
  2. Automated reminders and overdue escalation
  3. Attempt automated verification for technical fix items
  4. Monthly action item metrics report
  5. Quarterly action item audit

Large Team (50+ people)

Full action item management system needed. Core practices:

  1. Action item system integrated with incident management system — incidents auto-link to action items at creation
  2. Automated verification covering 50%+ of action items
  3. Grafana dashboard with real-time action item status
  4. Action item completion rate included in team KPIs
  5. Quarterly action item audit to evaluate improvement effectiveness
  6. Build action item knowledge base to accumulate historical experience

Summary

The real value of a postmortem is not in the meeting itself, but in whether the action items afterward actually land. Action item tracking is what turns “paper improvements” into “system improvements.”

The core lessons are few:

  1. Action items must have five elements: what, who, when, how to verify, what priority. Missing any one means it is not a proper action item.
  2. Use a tracking tool, not Excel. Jira, GitHub Issues, whatever — the key is having a state machine, reminders, and analytics.
  3. Automate verification whenever possible. Manual verification is the bottleneck. Translating acceptance criteria into executable check scripts significantly reduces the burden.
  4. Measure system effectiveness with data. Completion rate, MTTC, overdue rate, recurrence rate — these four metrics tell you whether the tracking system actually works.
  5. Maintain blameless culture. The purpose of action item tracking is to make the system more reliable, not to punish people. Once the culture turns to blame, action item quality degrades rapidly.

One last honest truth: action item tracking has no deep technical barrier. The hard part is sustained execution. No matter how good the tool or how elegant the process design, without someone watching, it fails. If your action item tracking system keeps getting built and abandoned, the problem is probably not the tool — it is the team’s commitment to taking it seriously. Get management to recognize the value of action item tracking first, and everything else falls into place.

References & Acknowledgments

This article referenced the following materials during writing. Thanks to the original authors for their contributions:

  1. Incident postmortems — Atlassian, describes the practice of tracking postmortem action items with Jira work items to ensure completion and approval
  2. How to Run Postmortems: Meitu SRE’s 10-Year Experience Summary — Meitu SRE Team, summarized the three golden postmortem questions (faster recovery, prevent recurrence, distill practices) and incident severity classification standards
  3. IT Operations Incident Postmortem Tool Guide: Full-Process Analysis from Emergency Response to Systematic Improvement — Tencent Cloud Developer Community, proposed structured postmortem framework and action item tracking mechanism
  4. Enterprise Operations Incident Postmortem Steps and Improvement Methods — Peng Huasheng, established a six-step postmortem improvement method around “postmortem approach, timeline, root cause analysis, improvement tracking, report publication”
  5. How to Run an Efficient Incident Postmortem? — Tencent Cloud Developer Community, analyzed problems with traditional Blame Game-style postmortems and root causes of action items being hard to follow up
  6. Can System Engineers Really Avoid Blame? See How Major Companies Do It! — TakinTalks Community Experts, proposed the “no blame, focus on improvement” incident culture and the accountability principle of “allow mistakes, but not repeated mistakes”