tag-audit — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited tag-audit (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.
Stacked-rebase sessions accumulate safety tags fast — each surgical operation deserves its own rollback anchor, but the cost of regret is high. Once an operation is validated and pushed, those tags decay into redundancy: they either duplicate another tag, point at the same SHA as a current branch ref, or mark an intermediate waypoint no one will ever git reset back to.
This skill audits the safety-tag namespace, surfaces duplicates by sorting on SHA (not name), proposes deletions with reasons, and deletes only after explicit confirmation.
session, when the operation's safety tags are no longer load-bearing.
/stack-cascade Step 2 refuses to proceed because the OP_IDnamespace is non-empty.
git tag -l 'safety/*' 'pre-*' 'post-*' returns more entries thanfeels healthy and you want to know which ones still earn their keep.
is unfamiliar.
rollback anchors.
reviewed, no surprises from teammates) — the rollback window is still open.
safety-tag pattern set — narrow the pattern set first.
A safety tag earns its keep only when it points at a unique, semantically-meaningful SHA AND that SHA represents a state you might genuinely need to git reset back to. Anything else is rollback theater — the deletion candidate. Step 3 implements this as a three-question decision tree.
Sort by SHA (not name). Name-grouped output hides duplicates; SHA-grouped output exposes them — tags pointing at the same commit cluster together, making redundancy visible at a glance.
# Default is conservative: only the canonical `safety/*` namespace.
# Keep in sync with Step 2 below.
PATTERNS=('safety/*')
(
set -euo pipefail
count=$(git tag -l "${PATTERNS[@]}" | wc -l | tr -d ' ')
echo "# Matched $count tag(s) across patterns: ${PATTERNS[*]}" >&2
[[ "$count" -gt 0 ]] || { echo "# (nothing to audit — check pattern typos or working directory)" >&2; exit 0; }
git tag -l "${PATTERNS[@]}" | while IFS= read -r t; do
# Capture-then-print: bare $(...) inside printf's arg list does NOT trigger
# set -e on substitution failure (the outer printf wins with exit 0).
# Capturing to a variable lets set -e fire if rev-parse fails.
# The ^{commit} peel returns the commit SHA for both lightweight AND
# annotated tags (bare rev-parse on an annotated tag returns the tag-object
# SHA, which won't cluster with branch SHAs in Step 2).
sha=$(git rev-parse --short "$t^{commit}") \
|| { echo "rev-parse failed for tag '$t' — aborting audit" >&2; exit 1; }
printf '%s TAG %s\n' "$sha" "$t"
done | sort
)The default ('safety/*') is intentionally conservative — it matches only the canonical namespace stack-cascade writes to under the current convention. Widen it explicitly for cleanup that covers other namespaces:
stack-*-start/* from cascades before the convention change.pre-mr/*,pre-port/*, pre-fix-*, post-fix-*, pre-split/*.
backup-*.PATTERNS=('safety/*' 'pre-*' 'post-*' 'backup-*' 'stack-*') # broad auditThe audit is read-only; widening the pattern is cheap. But leave the widened pattern in place for Step 5's deletion only after the KEEP/DROP review confirms no release tags or ad-hoc semantic tags slipped in (pre-1.0, pre-release-*, backup-2024-05, safety-audit-2026-q1). See "When NOT to Use" above.
Enumerate current branch tips by SHA, then interleave them with Step 1's output so SHA collisions between tags and branch refs are visible adjacently:
# Use the same PATTERNS as Step 1 (default safety/* OR your widened set).
PATTERNS=('safety/*')
(
set -euo pipefail
{
git tag -l "${PATTERNS[@]}" | while IFS= read -r t; do
# Same capture-then-print + ^{commit} peel as Step 1 — see comments there.
sha=$(git rev-parse --short "$t^{commit}") \
|| { echo "rev-parse failed for tag '$t' — aborting audit" >&2; exit 1; }
printf '%s TAG %s\n' "$sha" "$t"
done
git for-each-ref refs/heads --format='%(objectname:short) BRANCH %(refname:short)'
} | sort
)Any TAG line whose SHA matches an adjacent BRANCH line is a deletion candidate — the branch ref already serves as the anchor.
For each tag in the audit output, apply these three questions in order:
more recent or more descriptive name.
tag; the branch ref already anchors that SHA.
but adds no information now?** → drop unless it marks a uniquely meaningful state worth permanently anchoring (root snapshots, pre-cascade origin SHAs, anchors referenced in narrative docs).
A tag survives only when it has a unique SHA AND no equivalent branch ref AND marks a state genuinely worth git reset-ing back to.
Always show the proposal before any deletion. Example output (with widened patterns covering an ad-hoc pre-* / post-* session):
Found 21 safety tags. After audit:
KEEP (5 — unique semantically-meaningful SHAs):
3be7b11a pre-split/improved-disabled [root anchor]
4a9fac77 pre-split/pr10 [pre-cascade origin]
e5f1dd7d pre-split/pr11 [pre-cascade origin]
aa71726b pre-split/pr12 [pre-cascade origin]
f675fe31 pre-split/pr13 [pre-cascade origin]
DROP (16):
pre-mr/pr10-cascade [duplicate: same SHA as pre-fix-pr11ci/pr10]
pre-mr/pr11-cascade [duplicate: same SHA as pre-fix-pr11ci/pr11]
pre-fix-pr11ci/pr10 [branch-ref: SHA matches branch pr10]
post-fix-pr11ci/pr11 [branch-ref: SHA matches branch pr11]
post-fix-pr11ci/pr12 [branch-ref: SHA matches branch pr12]
post-fix-pr11ci/pr13 [branch-ref: SHA matches branch pr13]
pre-mr/pr9.6-post-triage [intermediate-waypoint]
pre-mr/pr9.6-post-c5 [intermediate-waypoint]
... (etc)
Proceed with deletion? [y/N]Reason codes: [duplicate], [branch-ref], [intermediate-waypoint], or a one-line free-text reason for KEEP entries ([root anchor], [pre-cascade origin], [narrative anchor]).
Two-pass verify-then-mutate under set -euo pipefail. Use quoted array iteration — bash unquoted-var word-splitting fails silently under zsh (see references/shell-portability.md).
TAGS_TO_DELETE=(
"pre-mr/pr10-cascade"
"pre-mr/pr11-cascade"
"pre-fix-pr11ci/pr10"
# ... full list from Step 4 DROP
)
(
set -euo pipefail
# Verify pass: confirm every tag exists before deleting any
for t in "${TAGS_TO_DELETE[@]}"; do
git rev-parse --verify "refs/tags/$t" >/dev/null 2>&1 \
|| { echo "Tag '$t' not found — aborting (no tags deleted)" >&2; exit 1; }
done
# Mutation pass: delete each
for t in "${TAGS_TO_DELETE[@]}"; do
git tag -d "$t"
done
)The verify pass is a pre-flight check: a missing tag name aborts before any deletion, so the namespace can't be left half-cleaned by a typo or a stale paste from Step 4. (Concurrent tag mutation by another process between the verify and mutate passes is still possible — this is shell, not a transaction. The window is narrow if you're the only writer.)
Most safety tags are local-only: git push does not push tags by default. Skip this step unless the tags were explicitly pushed (e.g., via git push --tags or a CI workflow that forwards tags).
When remote cleanup is needed, push deletion refspecs in a single atomic operation so a partial failure doesn't leave the remote half-cleaned:
TAGS_TO_DELETE=(
"pre-mr/pr10-cascade"
"pre-mr/pr11-cascade"
# ... same list as Step 5
)
(
set -euo pipefail
# Guard against empty array: `git push --atomic origin` with NO refspecs
# falls back to push.default and pushes the current branch — exactly the
# opposite of "delete zero remote tags".
[[ ${#TAGS_TO_DELETE[@]} -gt 0 ]] \
|| { echo "TAGS_TO_DELETE is empty — refusing to push" >&2; exit 1; }
refspecs=()
for t in "${TAGS_TO_DELETE[@]}"; do
refspecs+=(":refs/tags/$t")
done
git push --atomic origin "${refspecs[@]}"
):refs/tags/<name> is the deletion refspec; --atomic makes the multi-ref push all-or-nothing.
do git tag -d $t; done passes the whole string as one arg to git tag -d, which complains about a single-revision-not-found error. The loop "completes" without deleting anything. Always use quoted array iteration (for t in "${arr[@]}") or xargs. See references/shell-portability.md` for the full mitigation set.
git tag -l '*' isobviously dangerous, but safety-* accidentally matches a hand-named safety-audit-2026-q1 tag, or backup-* matches a release naming scheme. The proposal-before-delete gate at Step 4 is the safety net — read the KEEP/DROP list before confirming.
itself is the one you wanted to restore** — if the cascade's pushed state turns out to be wrong and you want to roll back, the safety tag was the rollback anchor. Branch tips can move; safety tags do not. This is why "rollback window closed" is a precondition: don't audit until you're committed to the current state.
operation is in progress in the same repo (a rebase paused on conflict, a cherry-pick mid-application) can delete tags the paused operation needs for --abort. Check git status first.
/stack-cascade/stack-cascade creates safety tags under safety/${OP_ID}/before/<branch> (and historically under stack-${PURPOSE}-start/<branch> before the convention change). Step 2 of /stack-cascade blocks if its OP_ID namespace is non-empty — that collision-check error names this skill as the remediation. The error shows a literal git tag -l 'safety/${OP_ID}/*' preview command; running this skill against that pattern set produces the targeted DROP list. For legacy stack-*-start/* tags, widen PATTERNS to include 'stack-*' in Step 1.
/stack-cascade and /rebase-validate compose tightly along the cascade flow: cascade executes, validate verifies meaning preservation. /tag-audit is a separate utility that pairs with cascade's tag namespace as post-success aftercare, but operates independently — it's useful for any safety-tag accumulation, not just cascades, and its preconditions (rollback window closed) decouple it from the cascade's session.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.