From 6cd08b14db94974be69cfa22a21aee3a1f1641fe Mon Sep 17 00:00:00 2001 From: Jimisola Laursen Date: Sat, 13 Jun 2026 19:00:07 +0200 Subject: [PATCH 1/2] ci: add skill reference doc consistency check Verifies every references/*.md file in a skill directory is listed in the skill's SKILL.md, docs/modules/ROOT/pages/skills.adoc, and README.md (and vice versa), so a future PR can't add or remove a reference doc and forget one of the listing locations. Also fixes a pre-existing gap: reqstool-overview.md was listed in SKILL.md but missing from skills.adoc and README.md. Signed-off-by: Jimisola Laursen --- .github/scripts/check-skill-reference-docs.sh | 51 +++++++++++++++++++ .github/workflows/validate-plugins.yml | 3 ++ README.md | 1 + docs/modules/ROOT/pages/skills.adoc | 3 ++ 4 files changed, 58 insertions(+) create mode 100755 .github/scripts/check-skill-reference-docs.sh diff --git a/.github/scripts/check-skill-reference-docs.sh b/.github/scripts/check-skill-reference-docs.sh new file mode 100755 index 0000000..bcad443 --- /dev/null +++ b/.github/scripts/check-skill-reference-docs.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +errors=0 +adoc="docs/modules/ROOT/pages/skills.adoc" +readme="README.md" + +# Forward check: every references/*.md on disk must be listed in +# SKILL.md, skills.adoc, and README.md +while IFS= read -r -d '' file; do + filename=$(basename "$file") + skill_dir=$(dirname "$(dirname "$file")") + skill_md="$skill_dir/SKILL.md" + + if ! grep -qF "references/$filename" "$skill_md"; then + echo "::error::$filename not referenced in $skill_md" + errors=1 + fi + if ! grep -qF "\`$filename\`" "$adoc"; then + echo "::error::$filename not referenced in $adoc" + errors=1 + fi + if ! grep -qF "**$filename**" "$readme"; then + echo "::error::$filename not referenced in $readme" + errors=1 + fi +done < <(find plugins -path '*/references/*.md' -print0) + +# Reverse check: every *.md filename listed in skills.adoc / README.md +# reference tables must exist on disk under some references/ directory +while IFS= read -r filename; do + [ -n "$filename" ] || continue + if ! find plugins -path "*/references/$filename" -type f | grep -q .; then + echo "::error::$filename listed in $adoc but not found under any references/ dir" + errors=1 + fi +done < <(grep -oE '`[A-Za-z0-9._-]+\.md`' "$adoc" | tr -d '`' | sort -u) + +while IFS= read -r filename; do + [ -n "$filename" ] || continue + if ! find plugins -path "*/references/$filename" -type f | grep -q .; then + echo "::error::$filename listed in $readme but not found under any references/ dir" + errors=1 + fi +done < <(grep -oE '\*\*[A-Za-z0-9._-]+\.md\*\*' "$readme" | tr -d '*' | sort -u) + +if [ "$errors" -ne 0 ]; then + exit 1 +fi + +echo "All skill reference docs are consistently listed." diff --git a/.github/workflows/validate-plugins.yml b/.github/workflows/validate-plugins.yml index f9f3d2d..7c713ca 100644 --- a/.github/workflows/validate-plugins.yml +++ b/.github/workflows/validate-plugins.yml @@ -31,3 +31,6 @@ jobs: find . -name "*.json" \ ! -path "./.git/*" \ | xargs -I{} sh -c 'jq empty "{}" && echo "OK: {}"' + + - name: Check skill reference docs are listed consistently + run: bash .github/scripts/check-skill-reference-docs.sh diff --git a/README.md b/README.md index 9dcb74b..ffd3fa0 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,7 @@ Uses the `reqstool` MCP server (`get_status` tool) when configured. Falls back t Bundled convention docs that are auto-applied when working with reqstool files: +- **reqstool-overview.md** — what reqstool is, architecture (system/microservice/external), YAML files, imports, filters, implementations, CLI basics - **reqstool-conventions.md** — overview of config fields and skill conventions - **reqstool-annotation-conventions.md** — `@Requirements` and `@SVCs` placement rules (Java, Python, TypeScript) - **reqstool-decomposition-conventions.md** — parent-child hierarchies, dot-notation IDs, lifecycle states diff --git a/docs/modules/ROOT/pages/skills.adoc b/docs/modules/ROOT/pages/skills.adoc index fcaa03b..e80d8c8 100644 --- a/docs/modules/ROOT/pages/skills.adoc +++ b/docs/modules/ROOT/pages/skills.adoc @@ -53,6 +53,9 @@ Bundled convention docs that guide the AI assistant: |=== | Reference file | Description +| `reqstool-overview.md` +| What reqstool is — architecture (system/microservice/external), YAML files, imports, filters, implementations, CLI basics + | `reqstool-conventions.md` | Entry point — config reference, links to other convention docs From 99ac3db8eff0f56ea84c2dcd0a83a58f1322b34e Mon Sep 17 00:00:00 2001 From: Jimisola Laursen Date: Sat, 13 Jun 2026 19:18:04 +0200 Subject: [PATCH 2/2] refactor(ci): address review feedback on skill reference doc check - cd to repo root so the script works regardless of invocation directory - extract a shared check_reverse helper to deduplicate the two reverse-check loops - document the format conventions each grep/regex depends on, and the intentional scope (entry-point docs like reqstool-conventions.md are not cross-checked, since their link format isn't standardized) - add a CI step that proves the check fails on an undocumented reference doc, using a throwaway fixture file Signed-off-by: Jimisola Laursen --- .github/scripts/check-skill-reference-docs.sh | 49 ++++++++++++------- .github/workflows/validate-plugins.yml | 11 +++++ 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/.github/scripts/check-skill-reference-docs.sh b/.github/scripts/check-skill-reference-docs.sh index bcad443..4acf00e 100755 --- a/.github/scripts/check-skill-reference-docs.sh +++ b/.github/scripts/check-skill-reference-docs.sh @@ -1,12 +1,26 @@ #!/usr/bin/env bash set -euo pipefail +cd "$(git rev-parse --show-toplevel)" + errors=0 adoc="docs/modules/ROOT/pages/skills.adoc" readme="README.md" -# Forward check: every references/*.md on disk must be listed in -# SKILL.md, skills.adoc, and README.md +# Forward check: every references/*.md on disk must be listed in: +# - the skill's SKILL.md, as `references/` +# - skills.adoc, as a backtick-wrapped `` (table cell) +# - README.md, as a bold **** (list item) +# +# NOTE: these patterns encode the *current* formatting conventions used in +# skills.adoc / README.md / SKILL.md. If those docs are reformatted (e.g. a +# different markup style for the reference tables/lists), this script must +# be updated in lockstep, or every entry will start failing. +# +# Scope: only these three listings are checked. Per-skill "entry point" +# docs (e.g. reqstool-conventions.md, which links to the other convention +# docs) are intentionally not cross-checked, since not every skill has one +# and its link format isn't standardized across skills. while IFS= read -r -d '' file; do filename=$(basename "$file") skill_dir=$(dirname "$(dirname "$file")") @@ -27,22 +41,23 @@ while IFS= read -r -d '' file; do done < <(find plugins -path '*/references/*.md' -print0) # Reverse check: every *.md filename listed in skills.adoc / README.md -# reference tables must exist on disk under some references/ directory -while IFS= read -r filename; do - [ -n "$filename" ] || continue - if ! find plugins -path "*/references/$filename" -type f | grep -q .; then - echo "::error::$filename listed in $adoc but not found under any references/ dir" - errors=1 - fi -done < <(grep -oE '`[A-Za-z0-9._-]+\.md`' "$adoc" | tr -d '`' | sort -u) +# reference tables must exist on disk under some references/ directory. +check_reverse() { + local file="$1" pattern="$2" strip_chars="$3" + local filename + while IFS= read -r filename; do + [ -n "$filename" ] || continue + if ! find plugins -path "*/references/$filename" -type f | grep -q .; then + echo "::error::$filename listed in $file but not found under any references/ dir" + errors=1 + fi + done < <(grep -oE "$pattern" "$file" | tr -d "$strip_chars" | sort -u) +} -while IFS= read -r filename; do - [ -n "$filename" ] || continue - if ! find plugins -path "*/references/$filename" -type f | grep -q .; then - echo "::error::$filename listed in $readme but not found under any references/ dir" - errors=1 - fi -done < <(grep -oE '\*\*[A-Za-z0-9._-]+\.md\*\*' "$readme" | tr -d '*' | sort -u) +# skills.adoc lists filenames as `reqstool-overview.md` (backtick-wrapped) +check_reverse "$adoc" '`[A-Za-z0-9._-]+\.md`' '`' +# README.md lists filenames as **reqstool-overview.md** (bold) +check_reverse "$readme" '\*\*[A-Za-z0-9._-]+\.md\*\*' '*' if [ "$errors" -ne 0 ]; then exit 1 diff --git a/.github/workflows/validate-plugins.yml b/.github/workflows/validate-plugins.yml index 7c713ca..1a22324 100644 --- a/.github/workflows/validate-plugins.yml +++ b/.github/workflows/validate-plugins.yml @@ -34,3 +34,14 @@ jobs: - name: Check skill reference docs are listed consistently run: bash .github/scripts/check-skill-reference-docs.sh + + - name: Verify the consistency check fails on an undocumented reference doc + run: | + fixture=plugins/reqstool/skills/reqstool-conventions/references/__ci-fixture-undocumented.md + echo "fixture" > "$fixture" + if bash .github/scripts/check-skill-reference-docs.sh; then + echo "::error::expected check-skill-reference-docs.sh to fail for an undocumented reference file" + rm -f "$fixture" + exit 1 + fi + rm -f "$fixture"