backlog · git:20261002.d33370c · 2026-10-02 · sha256 a72aeee103fc7478
backlog git:20261002.d33370cA
Immutable. This exact content never changes and is served at /api/v1/blob/a72aeee103fc7478.
---
name: backlog
description: >
Manage the project's tech debt backlog. Add, list, fix, wontfix, delete,
prioritize, and suggest batch actions on tracked issues. Used by audit
and review skills to persist findings, and directly by users to manage
accumulated debt. Modes: list [category], add [description], fix B-{N},
wontfix B-{N} [reason], delete B-{N}, stats, prioritize, suggest.
category: Utility
---
# zuvo:backlog — Tech Debt Management
Add, list, and manage backlog items. The backlog tracks technical debt discovered by audit skills, review agents, and manual entries.
**Backlog location:** `memory/backlog.md` at the **MAIN checkout root** — resolve worktree-safe per `../../shared/includes/backlog-protocol.md` ("Where the Backlog Lives"), full canonical block (copy BOTH lines — the fallback is mandatory, without it a non-git CWD yields `MAIN_ROOT=""` and re-forks the backlog):
```bash
MAIN_ROOT=$(git worktree list --porcelain 2>/dev/null | head -1 | sed 's/^worktree //')
[ -z "$MAIN_ROOT" ] && MAIN_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
```
NEVER create or write a `memory/backlog.md` inside a linked worktree — one backlog per repository. If `memory/` does not exist at MAIN_ROOT, create it. If the file does not exist, create it from the template at the bottom of this skill. If a legacy worktree-local copy exists, merge its unique entries (by the dedup key defined in `../../shared/includes/backlog-protocol.md`) into the main copy before proceeding.
**Scope:** Managing the tech debt backlog -- viewing, adding, resolving, prioritizing, and suggesting batch actions.
**Out of scope:** Actually fixing the issues (use `zuvo:fix-tests`, `zuvo:refactor`, or the suggested command from `suggest` mode).
## Argument Parsing
| Input | Action |
|-------|--------|
| _(empty)_ or `list` | Show all OPEN items as a summary table |
| `list category:[x]` | Show OPEN items filtered by category (code/test/arch/dep/doc/infra) |
| `list all` | Show all items including RESOLVED and WONTFIX |
| `add` | Interactive: ask what to add, then append |
| `add [description]` | Parse natural language description, add to backlog |
| `fix B-{N}` | Mark item as RESOLVED |
| `wontfix B-{N} [reason]` | Mark item as WONTFIX with reason |
| `delete B-{N}` | Remove item (show details, ask confirmation) |
| `delete B-{N} --force` | Remove without confirmation |
| `archive [--dry-run]` | Move ticked, resolution-marked entries to `memory/backlog-done.md` |
| `regression B-{N}` | Re-open an archived entry under the same id (lookup said ARCHIVED) |
| `stats` | Show counts by severity and category |
| `prioritize` | Score and rank all OPEN items by urgency |
| `suggest` | Group items by pattern, propose batch fix commands |
---
## The verification lane (`agents/backlog-verifier.md`)
Deciding whether an entry is **still true** is not one of the modes above, and it is not done inline.
It is dispatched, one byte-capped CHUNK at a time, to `agents/backlog-verifier.md` — a read-only lane
that returns one verdict and one evidence line per row.
The orchestration is in `scripts/zuvo-home/backlog-groom.py`, never in this file's prose:
| Step | Command |
|------|---------|
| mint, decide the deterministic classes, write the queue | `backlog-groom.py plan --repo . [--dry-run]` |
| hand one chunk to the lane, seeds mixed in | `backlog-groom.py dispatch --repo . --chunk N` |
| check the response and append only if nothing refused | `backlog-groom.py ingest --repo . --dispatch <D> --response <R>` |
Read `../../shared/includes/backlog-grooming.md` before using any of them. Two things about this lane
that are easy to get wrong and expensive to get wrong:
- **A chunk is all-or-nothing.** `ingest` writes ledger rows only when the rejection list is empty. One
bad record writes zero rows for every row the lane got right, so the check after a run is the
ledger's **byte count**, not the presence of one verdict.
- **The four mechanical controls do not validate a verdict.** Shape, resolvability and keyword overlap
establish that the evidence is well-formed and points at a real line — they cannot say the verdict is
correct. Only the seeded known-answers measure judgement, on K=4 rows per chunk. Never report a lane
result as verified or cross-checked.
Dispatch follows `../../shared/includes/execution-policy.md` through env-compat. Reuse existing
authorization within that policy; session restrictions take precedence. Run each required gate
and report its actual independence or an unmet requirement.
**Inline verification is NOT a substitute for the lane.** Deciding the rows yourself and recording the
result as if the lane had run is the substitution `no-gate-substitution` describes: it produces verdicts
with no `agent:` provenance for the cross-model spot check to select on, and it bypasses controls (a)-(d)
entirely while reporting that they ran. If the harness genuinely cannot dispatch, say so and record the
rows as unverified — `groom` then refuses, which is the correct outcome rather than a blocked one.
---
## Mandatory File Loading
### PHASE 0 — Bootstrap (before reading the backlog)
`env-compat.md` is here for one measured reason: this skill scans repositories and waits on the
commands that do it, and it accounted for **485 of 11,690 Codex poll calls** while referencing that
include nowhere — so the "do not enter the poll loop" rule could not reach it however well written.
Each poll re-sends the whole context (~108K tokens median) to learn one bit.
```
1. ../../shared/includes/codesift-setup.md -- [READ | MISSING -> WARN]
2. ../../shared/includes/backlog-protocol.md -- [READ | MISSING -> STOP] (the file format is the contract)
3. ../../shared/includes/env-compat.md -- [READ | MISSING -> WARN] (waiting rule; see below)
```
`retrospective.md` and `run-logger.md` are END-of-run includes — they are loaded at completion, not here.
## Run Logging
Read `../../shared/includes/run-logger.md` for log format and file path resolution.
Read `../../shared/includes/retrospective.md` for log format and file path resolution.
## CodeSift Integration
Read `../../shared/includes/codesift-setup.md` for initialization.
**Key tools for this skill:**
| Command | Task | CodeSift tool | Fallback |
|---------|------|--------------|----------|
| suggest | Find undiscovered TODO/FIXME debt | `search_text(repo, query="TODO\|FIXME\|HACK", regex=true)` | Grep |
| suggest | Context around TODO markers | `find_and_show(repo, query=<function>, include_refs=true)` | Read the file |
| prioritize | Count references to affected function | `find_references(repo, symbol_name=<fn>)` | Skip (score from description only) |
| prioritize | Blast radius of recent items | `impact_analysis(repo, since="HEAD~10", depth=2)` | Skip |
| fix | Find related code when planning a fix | `search_symbols(repo, query=<keyword>)` | Grep |
| fix | Batch-read related functions | `get_symbols(repo, symbol_ids=[...])` | Multiple Read calls |
---
## Backlog Schema
All interactions use these columns:
| Column | Description | Set by |
|--------|-------------|--------|
| ID | `B-{N}` sequential | Auto |
| Status | OPEN, RESOLVED, WONTFIX | Auto (default: OPEN) |
| Fingerprint | Dedup key (see format below) | Auto |
| File | File path | Required |
| Problem | Short description | Required |
| Severity | CRITICAL, HIGH, MEDIUM, LOW | Required |
| Category | Code, Test, Architecture, Dependency, Documentation, Infrastructure | Required |
| Source | Which skill added it | Auto |
| Seen | Occurrence count | Auto |
| Added | Date first added (YYYY-MM-DD) | Auto |
### Fingerprint Formats
- From audit skills: `file|rule_id|signature` (e.g., `auth.service.ts|cq8|missing-try-catch`)
- From test audit: `file|pattern_id|signature` (e.g., `auth.test.ts|p-41|loading-only`)
- Manual add: `file|manual|first-3-words-slugified` (e.g., `auth.ts|manual|missing-rate-limiting`)
All fingerprint components are lowercase, trimmed, with leading `./` stripped from paths.
### Listing View (compact)
Default view shows: `ID | Severity | File | Problem | Seen`
---
## Adding Items
When adding (interactive or from description):
1. Read the current `memory/backlog.md`
2. Determine the next `B-{N}` ID
3. If natural language input, extract:
- **File** (ask if not apparent from description)
- **Problem** (short description)
- **Severity** (infer from keywords -- see inference rules)
- **Category** (infer from file path)
4. Compute the key per `../../shared/includes/backlog-protocol.md` (id-preferred, content-fallback)
5. Dedup check across **both** files — run the lookup, do not re-implement it:
`~/.zuvo/backlog-archive.py lookup --repo "$MAIN_ROOT" "<candidate>"`
- `OPEN` (exit 10): update that entry in place — Seen, date, severity if worse. No duplicate.
- `ARCHIVED` (exit 11): **REGRESSION.** Re-open under the SAME id with the back-link the protocol
defines. Never mint a new id; never file it as a fresh finding.
- `ABSENT` (exit 0): append a new entry with a fresh id.
Checking only `backlog.md` is not a check — an entry that exists solely in `backlog-done.md`
reads as ABSENT and comes back as new work.
6. Confirm what was added
### Batch Add
If the user provides multiple issues (numbered list, bullets, or comma-separated), add them all in one pass. Show a summary table for confirmation before writing.
### Auto-Inference Rules
Do not ask per-item for batch adds. Infer missing fields:
- **Severity:** `race condition`, `security`, `data loss` -> HIGH. `any type`, `missing test` -> MEDIUM. `typo`, `naming` -> LOW.
- **Category:** `*.test.*` -> Test. `*.service.*`, `*.controller.*` -> Code. `docker*`, `*.yml` -> Infrastructure.
- **Source:** `manual`
- **Seen:** 1
- **Added:** today's date
---
## Resolving Items
`fix` and `wontfix` record the resolution on the entry and then ARCHIVE it. Neither removes the
record: the archive is what lets a later sighting be recognised as a regression instead of being
re-filed as new work.
- `fix B-{N}`: verify exists (error if not), tick the box and **append** `[FIXED <sha7>]` to the
existing text — never write over the problem description, because the description is what the
content key is computed from.
- `wontfix B-{N} [reason]`: verify exists, tick the box and append `WONTFIX — <reason>`.
- `archive [--dry-run]`: move every ticked, marker-carrying entry into `backlog-done.md` via
`~/.zuvo/backlog-archive.py archive --repo "$MAIN_ROOT"`. Entries holding a live `[ ]` sub-item are
refused, not moved — split them first.
- `regression B-{N}`: the `ARCHIVED` path of the lookup. Re-open under the same id with the
back-link, severity one band higher, and the word REGRESSION in the report.
- `delete B-{N}`: destructive and rarely right. Print "this destroys the record — `archive` is what
you want", show the item, ask "Delete? (y/n)". With `--force`, skip the confirmation only.
**Never archive by hand.** `~/.zuvo/backlog-archive.py archive` does it — with a lock, byte conservation, minted ids and the git-tracking refusal. What a hand-written archive breaks, and the measured incident behind the rule, are in `backlog-protocol.md` → "Archiving is done by the helper, never by hand" (kept there once rather than paraphrased here).
**Order, not growth control:** archive; never prune. A resolved entry does not stay in the open
backlog — it moves verbatim to `backlog-done.md`, so the record survives. There is **no size
threshold**: one resolved entry is already reason enough, and `~/.zuvo/append-runlog` does the move
automatically at the end of every run. `backlog-archive.py status` answers "is anything done still
sitting here?" — exit 12 yes, 0 no. A tick with no resolution marker also moves, into a section whose
heading says the reason was never recorded; only an entry with a live `[ ]` sub-item is held back.
See "When to archive" in the protocol.
---
## Listing Items
Default (`list`): show OPEN items only.
```
TECH DEBT BACKLOG -- [project name]
-----
| ID | Severity | File | Problem | Seen |
|------|----------|-------------------------|--------------------------|------|
| B-1 | MEDIUM | auth.service.ts | catch(err: any) | 3x |
| B-2 | HIGH | payout.service.ts | Race condition in claim | 1x |
-----
OPEN: X items (C: _, H: _, M: _, L: _)
```
---
## Stats
```
BACKLOG STATS
-----
OPEN: X items
CRITICAL: _
HIGH: _
MEDIUM: _
LOW: _
By category:
Code: _ Test: _ Architecture: _
Dependency: _ Documentation: _ Infrastructure: _
Top files (by item count, top 5):
1. services/payout.service.ts (3 items)
2. handlers/webhook.ts (2 items)
-----
```
---
## Prioritize
Score each OPEN item to produce a ranked list. The scoring formula:
```
Priority Score = (Impact + Risk) x (6 - Effort)
```
| Dimension | 1 | 3 | 5 |
|-----------|---|---|---|
| Impact | Rarely slows work | Sometimes blocks development | Slows the team every day |
| Risk | Nice to have | Regressions possible | Security or data loss risk |
| Effort | Multiple days | About a week | A month or more |
Score range: 2 (low priority) to 50 (fix immediately).
**CodeSift-enhanced scoring:** When indexed, use `find_references(repo, symbol_name=<function>)` to count callers. Higher reference count means larger blast radius, which increases Impact and Risk scores.
Output:
```
PRIORITIZED BACKLOG
-----
| Rank | ID | Score | Impact | Risk | Effort | Problem |
|------|------|-------|--------|------|--------|-----------------------|
| 1 | B-2 | 40 | 5 | 5 | 2 | Race condition payout |
| 2 | B-1 | 24 | 4 | 4 | 3 | catch(err: any) |
-----
```
---
## Suggest
Analyze all OPEN items by pattern and propose batch actions.
**CodeSift-enhanced discovery:** Before analyzing existing items, scan for undiscovered debt:
- `search_text(repo, query="TODO|FIXME|HACK|WORKAROUND", regex=true)` to find inline markers not yet tracked
- Cross-reference with existing fingerprints to avoid duplicates
- If CodeSift unavailable, analyze only existing backlog items
### Pattern Matching
| Condition | Suggested action |
|-----------|-----------------|
| 3+ items with the same CQ gate failure | `zuvo:code-audit [files]` or direct batch fix |
| 3+ items from test-audit with same pattern ID | `zuvo:fix-tests --pattern [ID] [path]` |
| 3+ items in the same module | `zuvo:refactor [module]` |
| 5+ low-tier items | `zuvo:code-audit --deep [path]` |
| No OPEN items | "Backlog is clear. Consider a periodic audit." |
If multiple patterns match the same items, show all matching suggestions.
Output:
```
BACKLOG SUGGESTIONS
-----
Pattern: CQ8=0 in 5 files -> zuvo:code-audit src/services/
Pattern: P-41 in 4 test files -> zuvo:fix-tests --pattern P-41 src/
Hotspot: offer.service.ts (6 items) -> zuvo:refactor src/offer/offer.service.ts
-----
```
---
## Error Handling
| Situation | Response |
|-----------|----------|
| `fix B-99` but B-99 not found | "B-99 not found. Run `zuvo:backlog list` to see current items." |
| `list` but backlog is empty | "Backlog is empty. Use `zuvo:backlog add` to track issues." |
| `add` with vague description (no file) | Ask for file path and specific problem |
| `prioritize` with 0-1 items | "Only N item(s) -- no ranking needed." |
| `suggest` with 0 items | "Backlog is clear. Consider scheduling a periodic audit." |
---
## Tech Debt Categories
| Alias | Category | Examples |
|-------|----------|----------|
| code | Code | Duplicated logic, magic numbers, any-types |
| arch | Architecture | Wrong data store, monolith boundaries |
| test | Test | Low coverage, flaky tests, missing integration tests |
| dep | Dependency | Outdated libraries, CVEs, unmaintained packages |
| doc | Documentation | Missing runbooks, outdated READMEs |
| infra | Infrastructure | Manual deploys, no monitoring, missing IaC |
---
## Completion
After completing any action, print:
```
BACKLOG COMPLETE
-----
Action: [list | add | fix | wontfix | delete | stats | prioritize | suggest]
Run: <ISO-8601-Z> backlog <project> - - <VERDICT> - <DURATION> <NOTES> <BRANCH> <SHA7> <INCLUDES> <TIER>
-----
```
### Retrospective (REQUIRED)
Follow the retrospective protocol from `retrospective.md`.
Gate check → structured questions → TSV emit → markdown append.
If gate check skips: print "RETRO: skipped (trivial session)" and proceed.
After printing this block, append the `Run:` line value (without the `Run: ` prefix) to the log file path resolved per `run-logger.md`.
`<DURATION>`: use the action label (`list`, `add`, `fix`, `wontfix`, `delete`, `stats`, `prioritize`, or `suggest`).
---
## Backlog Template
When `memory/backlog.md` does not exist, create it from this template:
```markdown
# Tech Debt Backlog
> Maintained by zuvo:review, zuvo:build, zuvo:code-audit, zuvo:test-audit, zuvo:write-tests, zuvo:fix-tests, zuvo:backlog.
| ID | Status | Fingerprint | File | Problem | Severity | Category | Source | Seen | Added |
|----|--------|-------------|------|---------|----------|----------|--------|------|-------|
```