Every team 'tracks' tech debt. Almost none of it gets read at the moment it matters — the moment someone is about to step on it. We moved our debt ledger into the repos themselves, with dated entries, explicit statuses, and superseded-not-deleted decisions. It has already prevented one production outage.
The Problem
Tech debt tracking fails in a specific, predictable way: the knowledge exists, but not where the next person is standing when they need it.
The ticket backlog is where debt goes to age. A "DEBT-412: shared state risk" ticket filed eight months ago does not stop the engineer who, today, is about to run terraform apply from the wrong directory. Wikis drift until nobody trusts them. And the worst failures are the silent ones — the debt nobody wrote down anywhere because it was discovered at 6pm in the middle of fixing something else.
We hit a textbook example during an infrastructure migration. Terraform had been split out of an application monorepo into a dedicated infra repo — but the old tree was left in place and still actively edited. Both trees pointed at the exact same remote state — same bucket, same key, per environment. Two independently evolving Terraform codebases, one state file. Either one could silently clobber the other's view of production. That is a five-alarm piece of tech debt, and it's exactly the kind that a backlog ticket does nothing about, because the person it will bite is mid-command, not mid-grooming-session.
There's a new forcing function too: AI agents. An agent works in your repos every day, loading whatever context lives there. Debt that's written down where the agent reads becomes something it routes around automatically. Debt that lives in a ticketing system it never opens gets re-stepped-on every single session.
The Solution: A Ledger in the Repo
We converged on a simple discipline: every repo carries its own debt ledger, in the same context files both humans and our AI tooling load by default. A few conventions make it work:
Dated entries with explicit status. Not "the CORS config might be inconsistent" but: audited on this date; the module copy in the new repo is missing the CORS resource the live tree added in commit X; applying as-written would delete live config; fixed in commit Y; verified — plan went from 1 destroy to 0. Every entry carries what was found, what state it's in now (fixed / validated-but-not-applied / open), and how it was verified. An entry you can't act on isn't a ledger entry, it's a worry.
Supersede, don't delete. When a decision gets reversed — and real decisions do — the old reasoning stays, annotated. We had a credentials-isolation decision overturned by a team lead with better context about which systems were genuinely per-environment versus singular. The ledger keeps both: original rationale, then "Superseded on date: ..." with the new reasoning. Six months from now, nobody re-litigates the decision from scratch, and nobody wonders whether the old approach was considered. It was; here's why it lost.
Root cause or it didn't happen. "The numbers don't match" is an observation. "The engine drops an entire premium category because the config generator defaults this flag off, and review never checks it against the actual payroll data — here's the file and line" is a ledger entry. We hold debt entries to the same standard as bug fixes: traced to mechanism, not symptom.
An open-items list that is actually short. Each ledger ends with current open items — the shared-state collision, an unpinned image tag that will repeat a known failure mode, a deferred sync waiting on someone else's in-flight work. Short enough to read at the start of any session that touches the repo. The backlog can hold a hundred items; the ledger holds the ones that can hurt you here.
What It Provided
It prevented a real production incident. That missing CORS rule above wasn't hypothetical: the rule was load-bearing (browser uploads bypass a WAF body-size limit by going straight to object storage), and the freshly split infra repo's copy of the module had silently lost it. A routine apply from the new repo would have deleted live config and broken a user-facing feature. It was caught because the migration ran as an audit with a ledger — every module diffed against the live tree, every discrepancy written down with a status — rather than a "move fast and trust the copy" exercise.
Known failure modes became recognizable in minutes. When an ECS deployment circuit breaker silently rolled back a config change (the deploy "succeeded," the change just wasn't there), the mechanism went into the ledger with a verification runbook: check the running task's definition ARN, not the service's pointer, not the pipeline's green check. The next occurrence was diagnosed in minutes instead of an afternoon, by matching symptoms against the written entry.
Debt got a voice in sequencing. Because the shared-state collision is written down as a structural risk — not a vague unease — it shapes decisions: the old tree's sync is deliberately deferred until in-flight work lands, and the "archive the old tree" conversation has a documented case behind it. Undocumented debt can't advocate for itself. Documented debt can.
And the AI agent respects it. This is the part that surprised me. The agent reads the ledger at session start like everything else in the context files — so it refuses to apply from the stale tree, flags the unpinned tag when someone touches the task definition, and carries corrections forward. The ledger isn't advisory documentation anymore; it's configuration for how work gets done.
Future Implications
The uncomfortable truth about tech debt was never that teams don't know about it. It's that the knowledge is stored where it can't intervene. A ledger entry that loads automatically — into the human's editor or the agent's context — at the moment someone touches the dangerous thing is worth fifty tickets.
AI raises the stakes in both directions. An agent without the ledger industrializes your mistakes: it will cheerfully repeat the same landmine-step across every session, at machine speed. An agent with the ledger industrializes your caution — every documented gotcha becomes a guardrail enforced on every future session, for free. The cost of writing down what you learned was always small. The return on it just went up by an order of magnitude. Put the ledger where the work happens.