tracking-sweep — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited tracking-sweep (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Cross-reference your assigned Jira tickets, beads, and GitHub PRs to flag drift across the portfolio. Read-only. Recommendations only — never auto-posts comments, never moves Jira status, never closes beads.
If a single branch looks suspicious during the sweep, recommend invoking tracking-auditor for that branch — don't replicate its logic.
/tracking-sweep # Full sweep
/tracking-sweep quick # Skip stale-beads + PR-detail fetches (faster)A drift report. Items that match across all three systems are NOT listed — only deviations. If there's no drift, the report is short. That's the point.
Run sections 1–3 in parallel (independent data fetches). Sections 4+ are sequential cross-referencing.
Tickets assigned to current user, not Done. Include the sprint custom field (customfield_10020) — the table both displays it and orders by it:
mcp__jira__jira_get
path: /rest/api/3/search/jql
queryParams:
jql: assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC
fields: summary,status,issuetype,priority,updated,parent,resolution,customfield_10020
maxResults: 50
jq: issues[*].{key: key, summary: fields.summary, status: fields.status.name, type: fields.issuetype.name, priority: fields.priority.name, updated: fields.updated, parent: fields.parent.key, sprint: fields.customfield_10020}The sprint field is an array of sprint objects. For each ticket extract the active sprint's name (first entry where state == "active"), else the most recent. Empty/null → — (no sprint — usually backlog).
If the result mentions a parent epic (e.g. AB-280), also fetch its other children so beads referencing sibling tickets can be resolved:
jql: parent = {epic-key}
fields: summary,status,assigneebd list --status=in_progress
bd list --status=open
bd memories # for parking notesIn quick mode skip:
bd stale # >14d no activity
bd orphans # broken dependenciesTwo PR queries serve different purposes. Run both.
3a — Org-wide list (catches orphans, recent context):
Reuse pr-status scripts (don't re-implement). The closed-list window is 28 days — long enough that infrequently-touched tickets aren't artificially zeroed, short enough that the orphan-detection pass stays fast:
~/.claude/skills/pr-status/scripts/gh-pr-list-open.sh
~/.claude/skills/pr-status/scripts/gh-pr-list-closed.sh "" 28 # last 28 daysThese return PRs across all repos in the org (the script uses gh search prs --owner $ORG, so e.g. yourorg/service-a PRs come back alongside yourorg/monorepo). This list feeds orphan-PR detection (Rule B) and the recent-PR context.
3b — Per-ticket targeted search (accurate PR counts in the table):
The 28-day window can still miss older PRs that shipped against tickets still in flight (e.g. a PR merged 6 weeks ago for a ticket still in Code Review awaiting verification). For every Jira ticket from step 1 (your assigned set, status != Done), do a targeted search by key — no time limit, all repos in the org:
~/.claude/skills/tracking-sweep/scripts/gh-pr-per-ticket.sh AB-649 AB-1107 AB-1121 ...Pass all non-Done Jira ticket keys as arguments. The script searches each key across the org with no time limit and outputs one JSON line per key: {"key":"AB-649","open":1,"merged":7,"prs":[...]}. Use open and merged counts directly for the table column.
Cost: one gh search prs per ticket. ~9 calls in a typical sweep, ~5–10s total. Worth it for accuracy.
In quick mode, skip 3b — fall back to whatever's in 3a's 28-day window. Counts may under-report; warn in the report header.
For each PR from step 3a (title + branch name where available) and each bead (title + description), extract Jira keys with regex [A-Z]+-[0-9]+. Build three maps:
pr_by_key: ticket-key → list of PRs. Merge the per-ticket results from 3b (authoritative for counts) with any extra PRs from 3a not yet captured.bead_by_key: ticket-key → list of beadsjira_by_key: ticket-key → ticket (your assigned set + sibling-epic children fetched in step 1)PRs from 3a with no extractable key go into orphans (used by Rule B). Beads with no extractable key likewise.
Run bd memories and look for entries that mention parked work (keywords: park, paused, behind, waiting on, intentional hold). Build a parked_keys set of ticket keys mentioned in parking memories. These suppress drift findings — see the "Parking" rule below.
Apply each rule. For each finding, record severity (❌ blocker / ⚠️ warning / ℹ️ info) and a concrete recommendation.
#### Rule A — Status mismatch (Jira ↔ reality)
For each Jira ticket assigned to you:
in_progress for it OR a PR is open for it → ⚠️ "Move to In Progress."in_progress or open for it → ⚠️ "Jira closed but bead still active — close bead or split off the remainder."#### Rule B — Orphan PRs
PRs (open OR recently merged) with no extractable Jira key in title/branch → ❌ "Untracked PR — link to a ticket or document why it's unticketed."
PRs with a Jira key that isn't in your assigned set or your epic's siblings → ℹ️ "PR references {key} which isn't yours — may be cross-team work, OK if intentional."
#### Rule C — Orphan beads
Open beads with no extractable Jira key → ⚠️ "Bead has no Jira link — add one or document intentional local-only scope."
Open beads referencing a Jira key that resolves to Done → ⚠️ "Parent {key} is Done; close this bead or re-link to a follow-up ticket."
Open beads referencing a Jira key that doesn't exist (404) → ❌ "Bead references {key} which doesn't exist — fix or close."
#### Rule D — Stale work (skipped in quick mode)
bd stale output → ℹ️ "Bead has had no activity in N days — close, defer, or progress."
bd orphans output → ❌ "Bead has a broken dependency — fix or close."
#### Rule E — Parking suppression
Before emitting any Status-mismatch finding from Rule A: check parked_keys from step 5. If the ticket key appears in a parking memory, suppress the finding and instead list it under "✅ Honoured parking" with a one-line note quoting the memory.
Be conservative: only suppress if the parking note clearly names the ticket. If the memory is vague, still emit the finding but mark severity as ℹ️ and add "_Possibly parked — check memory_".
Keep it tight. Skip empty sections. Order by severity.
Always render the assigned-tickets reference table first, then the drift sections. The table is a baseline so the user can sanity-check what was scoped and visually correlate drift findings against their full ticket list.
## Tracking Sweep — {YYYY-MM-DD HH:MM}
**Scope:** {N} Jira tickets · {M} beads (in_progress/open) · {K} PRs (open + last 28d, plus per-ticket history in full mode)
### 📋 Assigned Jira tickets
Mirror the column style of `/landscape`'s Jira table, extended with two cross-reference columns — **PRs** and **Beads** — which are the unique value of this skill.
| Sprint | Key | Type | Pri | Status | Updated | PRs (open/merged) | Beads (in_p/open) | Summary |
|--------|-----|------|-----|--------|---------|-------------------|-------------------|---------|
| Sprint 42 | [AB-649](…) | Task | P3 | Code Review | 2h | 1 / 9 | 0 / 0 | FE \| Ensure Session Id… |
| Sprint 42 | [AB-1107](…) | Task | P1 | In Progress | 3h | 0 / 3 | 0 / 0 | FE \| Add analytics events… |
| Sprint 41 | [AB-1121](…) | Task | P2 | Code Review | 7d | 0 / 0 | 0 / 0 | FE \| Send Device ID & Session ID… |
| — | [AB-678](…) | Task | P2 | Ready to Work | 4d | 0 / 0 | 0 / 0 | BE \| Update API Headers |Table rules:
S{N} if the column gets wide. — if none.https://yourorg.atlassian.net/browse/{key}).P1 Critical → P1, P2 High → P2, etc.2h, 4d).quick mode falls back to the 28-day window).Ordering (primary → secondary):
— (no sprint) last. Older-sprint rows are themselves a drift signal — carryover work.updated descending.After the table, add a one-line sprint summary like /landscape does: _All 6 in Sprint 42._ or _Spans 2 sprints: Sprint 42 (4), Sprint 41 (2), no-sprint (1)._ — answers "is this portfolio focused or scattered?" at a glance.
After the table, render drift findings:
---
### ❌ Blockers ({count})
- **{KEY}** — {one-line description}
→ _Recommendation:_ {concrete action}
### ⚠️ Drift ({count})
Group by category if more than 3 items:
**Status mismatches**
- **AB-1107** (In Progress) — all 3 linked PRs merged ≥10d ago, no in_progress bead.
→ _Recommendation:_ comment summarising shipped scope, transition to Test/Review (or confirm parking).
**Orphan beads**
- `myrepo-xyz` — no Jira link.
→ _Recommendation:_ link to a ticket or document local-only scope.
**Parent moved**
- `myrepo-abc` → AB-999 (Done).
→ _Recommendation:_ close bead.
### ℹ️ Info ({count})
- {Lower-priority observations.}
### ✅ Honoured parking
- **AB-1107, AB-1344** — parked behind AB-649 cookie work (per memory `regularly-cross-check-jira-ticket-status-against-beads`).
---
**Summary:** {N drift items} · {N blockers} · {N parked correctly}
**Suggested next step:** {one concrete action — usually the highest-severity item or a /tracking-auditor invocation for a suspicious branch}Drift findings should reference the table by key (e.g. "AB-1121"), letting the user glance up to see the full row rather than restating context.
If there's no drift at all:
## Tracking Sweep — {YYYY-MM-DD HH:MM}
✅ No drift. Jira, beads, and PRs are aligned across {N} tickets, {M} beads, {K} PRs.mcp__jira__jira_post, bd close, bd update, or gh pr edit. The skill recommends; the user acts.bd memories for parking notes before flagging status drift on a ticket. If parked, list under "Honoured parking" instead of "Drift."tracking-auditor rather than analysing the diff here./pr-status._Jira unavailable_ and continue._Jira MCP not configured — skipping Jira drift checks._. Beads and PR drift checks still run.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.