#!/usr/bin/env bash # Check every path:line citation in the map against the real tree. # # A card marked `verified` with a citation that no longer resolves is worse than no card, # so this runs cheap and often. It checks two forms: # `app/models/order.rb:137` full path from the repo root # `:137-148` shorthand, resolved against the card's `entity:` # It cannot tell you a citation points at the *wrong* line — only that the line exists. set -uo pipefail map_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" repo_root="$(cd "${map_dir}/../.." && pwd)" refs=$(mktemp) trap 'rm -f "$refs"' EXIT while IFS= read -r card; do rel="${card#"${repo_root}"/}" entity=$(awk '/^entity:/ { sub(/^entity: */, ""); print; exit }' "$card") grep -oE '[A-Za-z0-9_][A-Za-z0-9_./-]*\.(rb|yml|erb|md|js|sh|json):[0-9]+(-[0-9]+)?' "$card" \ | sort -u | while read -r ref; do printf '%s\t%s\t%s\n' "$rel" "${ref%:*}" "${ref##*:}" done >> "$refs" if [[ -n "$entity" ]]; then grep -oE '`:[0-9]+(-[0-9]+)?`' "$card" | tr -d '`' | sort -u | while read -r ref; do printf '%s\t%s\t%s\n' "$rel" "$entity" "${ref#:}" done >> "$refs" fi done < <(find "$map_dir" -name '*.md') total=0; bad=0 while IFS=$'\t' read -r card path spec; do total=$((total + 1)) full="${repo_root}/${path}" if [[ ! -f "$full" ]]; then echo "MISSING FILE ${card} -> ${path}" bad=$((bad + 1)); continue fi last="${spec##*-}" lines=$(wc -l < "$full") if (( last > lines )); then echo "LINE OUT OF RANGE ${card} -> ${path}:${spec} (file has ${lines} lines)" bad=$((bad + 1)) fi done < "$refs" echo "checked ${total} citations, ${bad} broken" [[ $bad -eq 0 ]]