It started with a screenshot. Every week, someone on our security team posted a vulnerability status update to an engineering channel. Active count, severity breakdown, which deadlines were about to blow, a few shout-outs for people who fixed things. It was good. It was also clearly done by hand, on a Friday, by a human who had better things to do.
I wanted to understand how it was made before I touched anything. So I treated it like a specification. Where did the numbers come from. What counted as "active." How was severity defined. What happened to the items that breached their deadline. The answer to most of these was "the issue tracker, read carefully by a person who knows where to look." That person was the program. Which is a polite way of saying the program was one keyboard away from a vacation.
The first thing I learned
The weekly report was not the work. The report was the visible tip of a much larger pile of operational labor: assigning owners, chasing deadlines, granting extensions, remembering which extension was about to expire. The writing was an hour. The remembering was the job.
That reframed the whole thing for me. I had assumed I was automating a report. I was actually automating memory.
The part I expected to be hard and wasn't
I wanted trend charts. Open versus closed over time, are we keeping pace with new findings, how long does remediation actually take. Standard advice says you start logging snapshots now and check back in three months. I did not want to wait three months.
Then I noticed every finding already carries a created date and a closed date. You can reconstruct the entire history from those two timestamps. For any week in the past, open equals created-by-then minus closed-by-then. The deadline data is right there too. I had a year of trend lines on day one, built from data the tracker had been quietly keeping the entire time. This remains my favorite part, mostly because it felt like cheating.
The part I expected to be easy and wasn't
Assigning owners. The scanner routes findings to whoever owns the code. When it cannot figure that out, the findings land in a default queue and sit there, aging toward their deadline, belonging to no one. The obvious fix is to assign someone. The obvious fix is also how you teach an entire engineering org to ignore you, because if you guess wrong often enough, your assignments become noise.
So I made a rule for myself: never assign a random person to clear a queue. Only assign when there is real signal. The signal already existed in the code-ownership file every team maintains, narrowed down to the person who actually keeps committing to that part of the codebase. When even that was unclear, the right move was to route to the team's manager and let them decide, not to invent an answer. The system proposes; a human confirms. Boring, and correct.
The part I keep reminding myself about
When something breaches its deadline, you have two honest choices: fix it, or formally accept the risk for a set window. The tempting third option is to let it sit and look away. Automating the creation of an exception record kills that third option. The breach now produces a tracked decision with an expiration date and a reminder.
The line I will not cross is letting the automation approve those exceptions. Creating the record is mechanical. Accepting risk is a judgment that belongs to a human with the authority to make it. A robot that grants itself permission to ignore security deadlines is not a program; it is a liability with a cron schedule.
Where it landed
The weekly report writes itself and waits for a human to hit send. The dashboard rebuilds from live data. A daily job routes the orphaned findings, opens exceptions on breaches, proposes owners for the unowned ones, and speaks up when someone quietly cancels a finding. A person still makes every decision that involves judgment. The machine handles the mechanical load and, mostly, the forgetting.
I set out to save someone an hour on Friday. What I actually built was a program that no longer depends on a single person remembering everything. That person can take the vacation now.