Triage debt
Skill KhurrumMahmood/senior-vibe-engineer/.claude/skills/triage-debt
Router-first engineering skills for AI coding agents: deliberate refactoring, architectural hygiene, ADRs, and bounded multi-language tooling.
npx -y skills add KhurrumMahmood/senior-vibe-engineer --skill triage-debtAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Cross-cutting aggregator that scores accumulated debt across the maintenance loop's outputs (find-* report stacks, spec drift, decision drift, hard-size-overflow specs, recurring same-target hits) and produces a ranked queue at `reports/triage-debt/scan-<TS>/queue.md`. Each entry names the recommended next skill to invoke (refactor-subsystem / fix-workflow / extract-* / decide). Top-5 highlighted. Pure read — never edits production code, never runs find-*; reads the cached evidence those skills already produced.
SKILL.md
16.8 KB, ~4.1k tokens by cl100k_base, as published. Nobody here has run it
/triage-debt
You are the orchestrator for the cross-cutting triage skill. The
deliverable is a ranked debt queue at
reports/triage-debt/scan-<TS>/queue.md whose top-N entries each
recommend a concrete next-skill invocation. You do NOT detect new
smells, do NOT run any /find-* skill, do NOT edit production code.
The whole point of this skill is to make accumulating debt visible across the maintenance loop's outputs. A single find-* run sees one slice; this skill compounds them so the user can prioritize without re-running every detector.
How success is judged
queue.mdis ranked by the Stage 2 score, and every top-N entry carries a one-line "why ranked here" rationale plus a concrete recommended-next skill invocation.- The inputs that fed the ranking are declared — which find-*
latestreports,specs-audit.json,decisions-audit.json, andeffectiveness.jsonlwere read, and which were missing. - The final reply names the cached input path, the copied input files, and any
unavailable axis from
inputs.md. Claims without that provenance do not satisfy the gate. - No new detection ran; no production code, spec, or decision status
was touched — the run writes only under
reports/triage-debt/scan-<TS>/.
Core beliefs
- Recurrence is the strongest signal. If
find-omnibushas flaggedcore/views/sites.pythree scans in a row and nothing has been done, that's worth more than a single P0 from a fresh scan elsewhere. - Spec drift is debt. A spec with IM-N items unchecked for 60+ days is either abandoned, blocked, or wrong — surface it so the user can decide which.
- Decision drift is debt. A
proposed-status ADR older than 30 days means the team didn't actually decide; either accept, deprecate, or supersede. - Hard size overflow is non-negotiable. A spec with
loc >= SIZE_HARD_LOC(1000) is over the architectural cliff; weight it heavily so it cannot be ignored. - Parking is real. A decision saying "leave foo alone until 2026-Q3" is a legitimate park; subtract score so the queue doesn't keep nagging.
- Mass findings mean a missing standard. When a single detector band yields ≥5 findings on one surface in its latest scan, the debt is one missing shared abstraction or convention — not N local bugs. Per-item fixes leave the generator in place; the queue entry must route to standardize-and-enforce instead (see Stage 3).
Scope (this skill itself)
- Project root: this worktree's root.
- Read:
reports/_meta/effectiveness.jsonl,reports/<smell>/latest/*.md(on-disk dirs use the smell name without thefind-prefix —reports/omnibus/, notreports/find-omnibus/), host-provided cachedspecs-audit.json,specs-size.json,decisions-audit.json, andeffectiveness.jsonl,ai-docs/decisions/(forparked_until:annotations). - Write:
reports/triage-debt/scan-<TS>/queue.mdand its input provenance record. - MAY write (debug only):
reports/triage-debt/scan-<TS>/raw-scores.json(the score breakdown per entry) — write only when debugging the scoring heuristic; no downstream stage or skill reads it.
Installed cache contract
This selected skill is an aggregator, not a copy of a host's spec or decision
registry. A copied install therefore consumes a host-owned cache directory
instead of invoking a repository checkout's audit or log scripts. Set
TRIAGE_CACHE to that directory; its default is
reports/triage-debt/cache/current. The cache may have been produced by the
host's own tools, but the installed skill does not require or import those
tools.
The exercised cache contains these plain-data files:
effectiveness.jsonl # skill, scan_id, target, findings_total, buckets, ts
specs-audit.json # spec path, last_modified, coverage summary
specs-size.json # hard-size overflow rows, or an empty list
decisions-audit.json # drift rows, or an empty list
Missing cache files are a declared unavailable input, not permission to infer
that an axis is clean. Copy the files that exist into the scan directory and
write inputs.md naming both present and missing inputs. Do not silently
recreate a registry audit or effectiveness logger from a partial checkout.
Pipeline
Stage 0 — Setup
TS=$(date +%Y%m%d-%H%M%S)
REPORT_DIR="reports/triage-debt/scan-${TS}"
mkdir -p "${REPORT_DIR}"
ln -sfn "scan-${TS}" reports/triage-debt/latest
TOP_N=5
while [ "$#" -gt 0 ]; do
case "$1" in
--top)
shift
if [ -z "${1:-}" ]; then
echo "error: --top requires N" >&2
exit 2
fi
TOP_N="$1"
;;
--top=*)
TOP_N="${1#--top=}"
;;
*)
echo "error: unknown argument: $1" >&2
exit 2
;;
esac
shift
done
case "${TOP_N}" in
''|*[!0-9]*)
echo "error: --top must be a positive integer" >&2
exit 2
;;
0)
echo "error: --top must be > 0" >&2
exit 2
;;
esac
Stage 1 — Collect inputs
Use the host's retained, read-only cache. This keeps the selected closure self-contained and lets a maintenance window triage retained evidence without re-running detectors:
TRIAGE_CACHE="${TRIAGE_CACHE:-reports/triage-debt/cache/current}"
{
echo "# Triage input provenance"
echo
echo "Cache: ${TRIAGE_CACHE}"
for input in effectiveness.jsonl specs-audit.json specs-size.json decisions-audit.json; do
if [ -f "${TRIAGE_CACHE}/${input}" ]; then
cp "${TRIAGE_CACHE}/${input}" "${REPORT_DIR}/${input}"
echo "- present: ${TRIAGE_CACHE}/${input}"
else
echo "- missing: ${TRIAGE_CACHE}/${input}"
fi
done
} > "${REPORT_DIR}/inputs.md"
Then enumerate per-skill latest symlinks:
# On-disk report dirs use the smell name without the find- prefix
# (reports/omnibus/, reports/dormant/, …). Keep find-<name> in the echo
# so the originating skill stays visible in the audit trail.
for smell in dormant duplication semantic-duplication \
omnibus implicit-state layer-violation \
query-mutation doc-route-drift route-sprawl \
frontend-contract-drift workflow-duplication; do
if [ -L "reports/${smell}/latest" ]; then
echo "find-${smell} → $(readlink reports/${smell}/latest)"
fi
done
Stage 2 — Score every candidate
A "candidate" is a (skill, target) pair. Build the candidate list by
walking the effectiveness log AND the latest find-* reports.
For each candidate, compute:
score = recurrence_count * 100
+ p0_finding_count * 50
+ spec_drift_days * 30 # if a spec mentions this target
+ decision_drift_days * 20 # if a decision applies_to this target
+ hard_size_overflow * 200 # if specs.py size-check flags it
+ age_weeks # tiebreak — older = slightly heavier
- parked_score # explicit park reduces priority
Definitions:
-
recurrence_count— number of distinct scan_ids ineffectiveness.jsonlfor this(skill, target)over the past 90 days. ≥3 = persistent. -
p0_finding_count— count offindings_totalfrom the most recent scan that landed in P0 buckets. The P0 bucket name varies per skill; use this map:Skill P0 bucket key find-omnibus confirmed_omnibusfind-layer-violation extract_servicefind-duplication merge_required(orcluster:P0-*in triage.md)find-semantic-duplication shape ≠ keep_separate_document_whyfind-implicit-state extract_enum_candidate+introduce_fk_candidatefind-query-mutation split_required+rename_requiredfind-dormant certain_deletefind-doc-route-drift broken_redirect+documented_onlyfind-route-sprawl cross_workflow_modulefind-frontend-contract-drift contract_breakfind-workflow-duplication authority_violationIf a skill's report doesn't fit this map (older format), fall back to
findings_total* 5 (lower weight, since uncategorized). -
spec_drift_days— for each spec where `coverage.summary.checkmark_lag0
ORnot_started > 0, the days since the spec'slast_modifiedinspecs-audit.json`. Cap at 60 (so a spec drifting 200 days doesn't swamp); below 60d, score 0 (drift is normal during active work). -
decision_drift_days— for each entry indecisions-audit.json.driftwith kindproposed_too_long, the days past 30. Forbroken_supersedes/applies_to_missing, score a flat 30 days. -
hard_size_overflow— 1 if cachedspecs-size.jsonlists this target asloc >= 1000, else 0. -
age_weeks— weeks since the most recenteffectiveness.jsonlentry for this candidate. Pure tiebreak. -
parked_score— readai-docs/decisions/*.mdfor any ADR with aparked_until: YYYY-MM-DDfield whoseapplies_to:overlaps the target AND the date is in the future. Score = 500 (effectively kicks it off the top-N).
Optionally write per-candidate breakdowns to
${REPORT_DIR}/raw-scores.json — only when debugging the scoring
heuristic; nothing downstream reads it.
Stage 3 — Build the queue
Sort all candidates by score descending. Highlight the top-N. For
each entry, determine the recommended next skill:
| Source skill | Recommended next |
|---|---|
| find-omnibus | /refactor-subsystem (decomposition mode) |
| find-layer-violation | /fix-workflow layer:<id> |
| find-duplication | /fix-workflow cluster:<id> |
| find-semantic-duplication | /unify-shadows then /fix-workflow semantic:<id> |
| find-implicit-state (extract_enum) | /extract-enum |
| find-implicit-state (introduce_fk) | /introduce-fk |
| find-query-mutation | /fix-workflow cluster:<symbol> |
| find-dormant | /fix-workflow delete:<id> |
| find-doc-route-drift | /prevent-regression topology:doc-route-drift |
| find-route-sprawl | /prevent-regression topology:route-ownership |
| find-frontend-contract-drift | /prevent-regression topology:frontend-boot |
| find-workflow-duplication | /extract-workflow-registry then /prevent-regression topology:workflow-registry |
| spec drift | /refactor-subsystem <spec-id> Phase 2b (Crystallize) |
| decision drift (proposed too long) | /decide --status accepted <slug> OR /decide --status deprecated <slug> |
| decision drift (broken chain) | /audit-decisions to inspect, then manual fix |
| hard size overflow | /find-omnibus <file> then /refactor-subsystem |
Mass-finding escalation (overrides the table). Before emitting an
entry, check the candidate's latest scan buckets (in
effectiveness.jsonl): if any single bucket holds ≥5 findings on one
surface, do NOT recommend per-item execution. The recommended next
becomes the standardize-and-enforce route:
/decide— name the standard or shared primitive the cluster implies (one ADR, not N tickets);- extract the primitive (the source skill's extract-* / refactor path);
/prevent-regression— pin the band so the cluster cannot regrow.
Annotate the entry escalated: mass-finding (<bucket> × <count>).
The canonical failure this prevents: a lifecycle scanner returns the
same missing-guard band 19 times across one route surface, and triage
emits 19 tickets — when the right shape was one shared primitive plus
one guard.
Stage 4 — Write queue.md
# Triage queue — scan-<TS>
_Aggregated from <N> find-* reports, <M> specs, <K> decisions over the
past 90 days._
## Top <TOP_N> (recommended next actions)
### 1. <target> — score <S>
- **Source:** `<skill>` (last seen <date>, hit <recurrence_count> times)
- **Why ranked here:** _one-line reason — recurrence / hard-size /
drift / etc._
- **Recommended next:** `/<skill> <args>`
- **Escalation:** _(when triggered)_ standardize-and-enforce — band `<bucket>` × <count>
- **Evidence:** `reports/<smell>/latest/<file>`
### 2. ...
## Full queue
| Rank | Target | Source skill | Score | Recurrence | P0 | Drift | Park |
|---|---|---|---|---|---|---|---|
| 1 | ... | ... | 350 | 3 | 5 | 60d | — |
## Park notes
- `<target>` parked by ADR `NNNN` until `<date>` — `<reason>`
## Stale find-* reports
_Reports older than 30 days where re-running the detector would refresh
the signal._
- `find-omnibus` last ran <date> on `<target>` — consider re-running.
Stage 5 — Record provenance
The output's inputs.md is the run record for a copied install. Do not append
to a host effectiveness log unless that host explicitly offers its own logging
command and the user asked to use it. The queue must state the cache path and
every unavailable axis, so an old or partial cache cannot look like a clean
audit.
Stage 6 — Summarize
Report to the user in ≤8 lines:
- Path to
queue.md. - Total candidates / top-N called out.
- 1-line for each top-3 with the recommended next command.
- Stale-report count (re-run signals).
- Name the Stage 1 cache path and any unavailable input axis from
inputs.md.
Non-goals
- Detecting new smells (each
/find-*skill owns its detection). - Editing production code.
- Mutating decision or spec status.
- Running
/refactor-subsystemor/fix-workflowfor the user — the recommendation is the deliverable; the user invokes the next skill.
When things go sideways
| Symptom | Action |
|---|---|
effectiveness.jsonl is empty | Note "no run history yet" in queue.md; rely on latest find-* reports only |
No find-* latest symlinks exist | Note "no recent detection runs"; recommend running the SUSPECT skills first |
Cached specs-audit.json is absent | Record it in inputs.md; do not score spec drift or claim it is clean. |
Cached decisions-audit.json is absent | Record it in inputs.md; do not score decision drift or claim it is clean. |
| Every top-5 entry is the same target | Real signal — that target is the worst debt; recommend /refactor-subsystem if it's a file, /decide if it's a missing decision |
| Top score is < 50 | Note "no urgent debt — maintenance loop is healthy"; queue.md still useful as a snapshot |
| Candidate has no recommended-next mapping | Default to /which-skill <target> so the user can hand-pick |
Replay case
For parser or scoring changes, replay the smallest executable boundary:
set -- --top 10
TOP_N=5
while [ "$#" -gt 0 ]; do
case "$1" in
--top)
shift
if [ -z "${1:-}" ]; then
echo "error: --top requires N" >&2
exit 2
fi
TOP_N="$1"
;;
--top=*)
TOP_N="${1#--top=}"
;;
*)
echo "error: unknown argument: $1" >&2
exit 2
;;
esac
shift
done
case "${TOP_N}" in
''|*[!0-9]*)
echo "error: --top must be a positive integer" >&2
exit 2
;;
0)
echo "error: --top must be > 0" >&2
exit 2
;;
esac
printf '{"top_n": %s}\n' "${TOP_N}" | python3 -m json.tool
The replay passes only when TOP_N is 10, the JSON parses, and the
transcript is pasted into the repair or closeout report.
What ships with it: 1 file
496 B alongside SKILL.md