Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion skills-codex/.agentops-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@
{
"name": "heal-skill",
"source_skill": "skills/heal-skill",
"source_hash": "bae0dc8ce6e916ad059776627ce2f94a42ed1ef15ff9c169f07ecd3cfb2f8c5e",
"source_hash": "901f981bf69ce82bfc7535b38241c672c0465978c6aaaa3f91cc5176c47a1b91",
"generated_hash": "0a4b01de799212b1c33f718aba85c1ea0e03a033542a8e81929ddbd52425ab4b"
},
{
Expand Down
2 changes: 1 addition & 1 deletion skills-codex/heal-skill/.agentops-generated.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"generator": "manual-maintained",
"source_skill": "skills/heal-skill",
"layout": "modular",
"source_hash": "bae0dc8ce6e916ad059776627ce2f94a42ed1ef15ff9c169f07ecd3cfb2f8c5e",
"source_hash": "901f981bf69ce82bfc7535b38241c672c0465978c6aaaa3f91cc5176c47a1b91",
"generated_hash": "0a4b01de799212b1c33f718aba85c1ea0e03a033542a8e81929ddbd52425ab4b"
}
25 changes: 23 additions & 2 deletions skills/heal-skill/scripts/heal.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ while [[ $# -gt 0 ]]; do
esac
done

# Find repo root (location of skills/ directory)
# Find repo root (location of skills/ directory). HEAL_REPO_ROOT overrides for
# fixture-driven tests (tests/scripts/heal-dispositions.bats); production derives
# it from the script location.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
REPO_ROOT="${HEAL_REPO_ROOT:-$(cd "$SCRIPT_DIR/../../.." && pwd)}"
SKILLS_ROOT="$REPO_ROOT/skills"

# If no targets, scan all skill dirs (skills/ and skills-codex/)
Expand Down Expand Up @@ -459,6 +461,25 @@ for skill_check in "$SKILLS_ROOT"/*/SKILL.md; do
fi
done

# Check 12: Dispositions coverage (global, not per-skill). Every user-invocable
# skills/<n> must have a row in docs/contracts/skill-dispositions.yaml. This is
# the gate that silently passed when /burndown (ag-3yl8 #600) was added, costing
# a CI round — heal --strict now catches it locally (ag-cw2y item 1).
DISPOSITIONS_FILE="$REPO_ROOT/docs/contracts/skill-dispositions.yaml"
if [[ -f "$DISPOSITIONS_FILE" ]]; then
for skill_check in "$SKILLS_ROOT"/*/SKILL.md; do
[[ -f "$skill_check" ]] || continue
check_dir="$(dirname "$skill_check")"
check_name="$(basename "$check_dir")"
# Skip internal/non-invocable skills (same exemptions as catalog check).
if grep -q 'user-invocable: false' "$skill_check" 2>/dev/null; then continue; fi
if grep -q 'internal: true' "$skill_check" 2>/dev/null; then continue; fi
if ! grep -qE "^[[:space:]]*-[[:space:]]+skill:[[:space:]]+${check_name}[[:space:]]*$" "$DISPOSITIONS_FILE" 2>/dev/null; then
report "MISSING_DISPOSITION" "$check_dir" "user-invocable but has no row in docs/contracts/skill-dispositions.yaml"
fi
done
fi

if [[ $FINDINGS -gt 0 ]]; then
echo ""
echo "$FINDINGS finding(s) detected."
Expand Down
53 changes: 53 additions & 0 deletions tests/scripts/heal-dispositions.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bats
# Regression for ag-cw2y item 1: heal --strict must flag a user-invocable skill
# that has no row in docs/contracts/skill-dispositions.yaml. This is the exact
# gate that silently passed when /burndown (ag-3yl8 #600) was added, costing a
# CI round. The check is fixture-driven via the HEAL_REPO_ROOT override.

setup() {
HEAL="$BATS_TEST_DIRNAME/../../skills/heal-skill/scripts/heal.sh"
FIX="$(mktemp -d)"
mkdir -p "$FIX/skills/foo" "$FIX/docs/contracts"
cat > "$FIX/skills/foo/SKILL.md" <<'EOF'
---
name: foo
description: A fixture skill for the dispositions coverage check.
skill_api_version: 1
---
# foo
EOF
cat > "$FIX/docs/contracts/skill-dispositions.yaml" <<'EOF'
dispositions:
- skill: bar
domain: "BC1 Corpus"
hexagonal_role: domain
disposition: keep
rationale: "unrelated existing row"
EOF
}

teardown() { rm -rf "$FIX"; }

@test "heal flags a user-invocable skill missing from skill-dispositions.yaml" {
run env HEAL_REPO_ROOT="$FIX" bash "$HEAL" --check skills/foo
[[ "$output" == *"MISSING_DISPOSITION"* ]]
[[ "$output" == *"foo"* ]]
}

@test "heal does NOT flag a skill that has a dispositions row" {
cat >> "$FIX/docs/contracts/skill-dispositions.yaml" <<'EOF'
- skill: foo
domain: "BC1 Corpus"
hexagonal_role: domain
disposition: keep
rationale: "now covered"
EOF
run env HEAL_REPO_ROOT="$FIX" bash "$HEAL" --check skills/foo
[[ "$output" != *"MISSING_DISPOSITION"* ]]
}

@test "heal --strict exits non-zero and names the missing disposition" {
run env HEAL_REPO_ROOT="$FIX" bash "$HEAL" --check --strict skills/foo
[ "$status" -eq 1 ]
[[ "$output" == *"MISSING_DISPOSITION"* ]]
}
Loading