From 094b317a8317a63b2a6a2f37fa11f200f8a1de99 Mon Sep 17 00:00:00 2001 From: atlas Date: Tue, 9 Jun 2026 09:02:42 +0200 Subject: [PATCH] ci: add a warn-mode lint for tracker tags in source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hive convention is prose, not tracker tags, in code, but it was enforced only at review time — three PRs this session needed request-changes purely for stray tags in new comments. Add scripts/check-issue-refs.sh: scans tracked source (rust, nix, js, ts, css, html; markdown exempt) for a hash followed by an issue number and emits a CI warning annotation per hit. The pattern is a hash, 2-5 digits, then a non-hex char or end-of-line, so it skips CSS hex colours (letter-bearing or six/eight-digit) while catching tags; a pure-numeric short hex is the only residual false positive (dodge with the six-digit form). Wire it into the CI workflow as a fast pre-check before nix flake check. It runs in warn mode (exit 0) so it does not block while the legacy backlog is cleaned up; the script takes a warn|deny arg so the later flip to a hard gate is a one-word change, not a rewrite — the same rollout shape as tightening a clippy lint. --- .forgejo/workflows/ci.yml | 7 ++++++ scripts/check-issue-refs.sh | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100755 scripts/check-issue-refs.sh diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 9ea39dec..a2b83696 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -10,6 +10,13 @@ jobs: runs-on: [hive-ci] steps: - uses: actions/checkout@v3 + - name: lint tracker tags + # Fast pre-check: flags hash-number tracker tags in source + # (hive convention is prose, not tags — /knowledge/hive-rules.md). + # Phase 1 is warn-only while the legacy backlog is cleaned up; + # flip the arg to `deny` for a hard gate once the tree is clean. + # See scripts/check-issue-refs.sh. + run: sh scripts/check-issue-refs.sh warn - name: check # Runs all flake checks: formatting (treefmt+rustfmt), cargo test, # cargo clippy, and module evaluation. No --no-build: the checks diff --git a/scripts/check-issue-refs.sh b/scripts/check-issue-refs.sh new file mode 100755 index 00000000..fcae50a6 --- /dev/null +++ b/scripts/check-issue-refs.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# CI lint: flags tracker tags (a hash followed by an issue number) in +# source comments. The hive convention is prose, not tracker tags, in +# code (see /knowledge/hive-rules.md) — tags rot, they point at moving +# targets and leak tracker coupling into the source tree. +# +# Usage: check-issue-refs.sh [warn|deny] +# warn (default): emit a CI warning annotation per hit, exit 0. +# deny: same annotations, but exit 1 if any hit is found. +# +# Rollout: starts in `warn` while the legacy backlog is cleaned up, +# then flips to `deny` for a hard gate (the clippy-stricter playbook). +# +# Scope: tracked *.rs *.nix *.js *.ts *.css *.html. Markdown is exempt +# (prose docs may legitimately cite the tracker). The pattern matches a +# hash, 2-5 digits, then a non-hex char or end-of-line: that trailing +# class skips CSS hex colours (letter-bearing or 6/8-digit) while still +# catching tracker tags. Residual: a pure-numeric short hex (e.g. three +# identical digits) trips it — write the six-digit form to dodge. +set -eu + +mode="${1:-warn}" +case "$mode" in + warn | deny) ;; + *) + echo "usage: $0 [warn|deny]" >&2 + exit 2 + ;; +esac + +pattern='#[0-9]{2,5}([^0-9a-fA-F]|$)' + +# `/dev/null` forces grep to always print a filename prefix, even when +# xargs hands it a single file. `-r`/`-0` keep it robust to odd paths +# and an empty file list. +hits="$( + git ls-files -z '*.rs' '*.nix' '*.js' '*.ts' '*.css' '*.html' \ + | xargs -0 -r grep -nE "$pattern" /dev/null 2>/dev/null || true +)" + +if [ -n "$hits" ]; then + echo "$hits" | while IFS=: read -r file lineno _; do + printf '::warning file=%s,line=%s::tracker tag in source — write prose, not a hash-number tag (see /knowledge/hive-rules.md)\n' "$file" "$lineno" + done + count="$(printf '%s\n' "$hits" | wc -l | tr -d ' ')" + printf 'check-issue-refs: %s tracker tag(s) found in source\n' "$count" >&2 + [ "$mode" = deny ] && exit 1 +fi +exit 0