# Issue Ledger

> Record an issue you found but are not fixing now, so that it is still actionable months later, and close one with evidence. Use whenever an audit, review or unrelated task surfaces a problem that is out of scope, and whenever marking a tracked item done.

- Skill: `chinthakat/issue-ledger` (Agent Skill)
- Install (CLI): `npx skillmds@latest add chinthakat/issue-ledger`
- Raw SKILL.md: https://api.skillmd.com/api/skills/chinthakat/issue-ledger/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: chinthakat (https://skillmd.com/u/chinthakat)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/chinthakat/issue-ledger

---


# The issue ledger

Work finds problems that are not the work. The choice is between fixing them
now (scope creep), forgetting them (the usual outcome), and writing them down
in a form that survives.

Most trackers fail at the third. An entry reading *"the export is broken for
some users"* is worse than nothing — it carries enough guilt to keep it alive and
not enough information to act on.

## 1. What an entry must contain

A stable id, and then:

| Field | Why |
|---|---|
| **What is wrong** | One sentence, stated as an observation |
| **Entity ids** | The exact rows, files, routes or records. Not descriptions |
| **Where it was measured** | Which environment, which layer, which date |
| **How to see it again** | The command, query or steps |
| **What is affected** | Who experiences it, how often |
| **Why it was not fixed** | Scope, risk, needs a decision, needs access |
| **What fixing it would take** | Even a rough shape |

**Entity ids are the field people skip and the one that matters most.** Titles
get edited, counts change, "the third item on the dashboard" moves. Six months
later, an entry with ids can be re-checked in a minute; an entry without them
has to be re-investigated from scratch, and usually is not.

## 2. Separate what you saw from what you concluded

```
Observed: 12 records (ids: a1b2, c3d4, ...) have status 'active' with no owner.
Inferred: probably the 2026-03 import, which did not set owner.
```

The observation stays true. The inference is a hypothesis from the state of your
knowledge on the day, and it is frequently wrong — the fix that follows an
unchallenged old inference is a rewrite of the wrong thing.

Keep them on separate lines. Label them.

## 3. Record the layer and the date

*"Eight courses have no assessment"* is not a fact on its own. Measured against
source files in March, it may never have been true of what users were served,
and it is certainly not true now.

Every count carries the environment it was measured in and the date it was
measured. Both. An old number without a date will be read as current.

## 4. Write it for a stranger

The reader is someone else, or you having forgotten everything. Assume no
context from the conversation that produced the entry.

- Expand the abbreviation the first time.
- Link the file, the run, the log, the conversation.
- Say what "broken" means concretely — what the user sees, versus what they
  should see.
- Include the failing output, trimmed to the part that matters.

## 5. Closing an entry states what was verified

`DONE` on its own is an assertion. What belongs there instead:

```
DONE 2026-09-21 — backfilled owner on all 12; re-ran the audit against
production, 0 matches. Import fixed at src/import/owner.ts:44 so it cannot
recur. Verified in the UI for a1b2.
```

Three things: **what changed**, **how it was confirmed**, and **whether the
cause is fixed or just the symptom**. An entry closed without the third one
comes back, and nobody realises it is the same problem.

Closing as "not doing this" is a legitimate outcome and deserves the same
treatment: why, and what would change the decision.

## 6. Triage, or the ledger becomes a graveyard

A list that only grows stops being read, and once it stops being read, adding to
it is just filing.

- Give each entry a severity, and define what the levels mean.
- Review the list on a cadence. Close what is stale, merge duplicates, reject
  what will never be done.
- Watch for clusters — five entries about the same subsystem is one entry about
  that subsystem.
- Keep it in the repository, next to the code, in version control. The history
  of the ledger is itself informative, and a tracker somewhere else is a tracker
  nobody opens while working.

## 7. Reference the id everywhere

Put the id in the commit message, the branch name, the code comment for a
deliberate workaround, and the test that pins the current behaviour. That is
what makes the ledger navigable in both directions — from an entry to the work,
and from a strange line of code to the reason it exists.

## Template

```markdown
### PI-142 — Export omits archived items for some tenants

**Status:** OPEN · **Severity:** 2 · **Found:** 2026-09-21 (production)

**Observed:** CSV export for tenants t_88f2, t_91ac omits items with
status='archived'. Ids: it_3391, it_3392, it_4410.
Reproduce: `node scripts/export.js --tenant t_88f2 --prod` then grep for it_3391.

**Inferred:** the export filter was copied from the picker query, which
correctly excludes archived. Not confirmed.

**Impact:** tenants using exports for their own audit trail lose history.
2 tenants confirmed; not measured across all.

**Not fixed because:** changing the filter changes every export; needs a
decision on whether archived rows belong in the default export or behind a flag.

**Shape of a fix:** separate query for export; add `--include-archived`.
```

## Checklist

- [ ] Stable id, referenced from commits and code comments
- [ ] Entity ids recorded, not descriptions
- [ ] Environment and date on every measurement
- [ ] Observation and inference separated and labelled
- [ ] Reproduction steps that work without the original context
- [ ] Reason it was not fixed, and the shape of a fix
- [ ] Closure states what changed, how it was verified, and whether the cause is fixed
- [ ] Ledger in version control and reviewed on a cadence

