diff --git a/scripts/append-skill-disposition.sh b/scripts/append-skill-disposition.sh new file mode 100755 index 000000000..46bf3b7d5 --- /dev/null +++ b/scripts/append-skill-disposition.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# append-skill-disposition.sh — ensure a new skill has a row in +# docs/contracts/skill-dispositions.yaml (ag-cw2y item-1 scaffold-half). +# +# Idempotent: appends a placeholder row only if the skill has none, so a +# newly-scaffolded skill is one-shot-green against heal.sh Check 12 +# (MISSING_DISPOSITION). The placeholder uses a real bounded context so +# check-bounded-contexts-drift.sh passes; the author refines domain / +# hexagonal_role / disposition / rationale during content fill (mirrors the +# "manual content fill required" contract of the SKILL.md skeleton). +# +# Usage: append-skill-disposition.sh [repo-root] +set -euo pipefail + +SKILL="${1:?usage: append-skill-disposition.sh [repo-root]}" +REPO_ROOT="${2:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +FILE="$REPO_ROOT/docs/contracts/skill-dispositions.yaml" + +if [[ ! -f "$FILE" ]]; then + echo "append-skill-disposition: no dispositions file at $FILE" >&2 + exit 1 +fi + +if grep -qE "^[[:space:]]*-[[:space:]]+skill:[[:space:]]+${SKILL}[[:space:]]*$" "$FILE"; then + echo "append-skill-disposition: '$SKILL' already present — no-op" + exit 0 +fi + +cat >> "$FILE" < "$BUILD_REPORT" <&2 +fi +# 2. Narrative skill counts — --fix-counts bumps the "N checked-in skills" tokens +# in the domain-map + bdd Gherkin so the new skill doesn't trip registry-drift. +if [[ -x "$REPO_ROOT/scripts/check-registry-drift.sh" ]]; then + bash "$REPO_ROOT/scripts/check-registry-drift.sh" --fix-counts >/dev/null 2>&1 \ + || echo "init.sh: WARN registry-drift --fix-counts could not run — bump counts manually" >&2 +fi + echo "init.sh: created skill skeleton at $NEW_DIR" echo "init.sh: codex parity at $CODEX_DIR" echo "init.sh: build report at $BUILD_REPORT" +echo "init.sh: dispositions row + narrative counts scaffolded (refine the placeholder row)" diff --git a/tests/scripts/append-skill-disposition.bats b/tests/scripts/append-skill-disposition.bats new file mode 100644 index 000000000..0b7e4c7a2 --- /dev/null +++ b/tests/scripts/append-skill-disposition.bats @@ -0,0 +1,49 @@ +#!/usr/bin/env bats +# ag-cw2y item-1 scaffold-half: skill-builder must append a skill-dispositions.yaml +# row for a new skill so it is one-shot-green against heal.sh Check 12. The helper +# is idempotent and repo-root-injectable (so init.sh can call it and tests can +# fixture it). + +setup() { + HELPER="$BATS_TEST_DIRNAME/../../scripts/append-skill-disposition.sh" + FIX="$(mktemp -d)" + mkdir -p "$FIX/docs/contracts" + cat > "$FIX/docs/contracts/skill-dispositions.yaml" <<'EOF' +dispositions: + - skill: existing + domain: "BC1 Corpus" + hexagonal_role: domain + disposition: keep + rationale: "already here" +EOF +} + +teardown() { rm -rf "$FIX"; } + +@test "appends a dispositions row for a new skill" { + run bash "$HELPER" newskill "$FIX" + [ "$status" -eq 0 ] + grep -qE "^[[:space:]]*-[[:space:]]+skill:[[:space:]]+newskill[[:space:]]*$" "$FIX/docs/contracts/skill-dispositions.yaml" +} + +@test "appended row carries a valid BC domain and a TODO rationale" { + bash "$HELPER" newskill "$FIX" + # The row's domain must be a real bounded context (so check-bounded-contexts-drift passes) + run grep -A4 'skill: newskill' "$FIX/docs/contracts/skill-dispositions.yaml" + [[ "$output" == *"BC4 Factory"* ]] + [[ "$output" == *"TODO"* ]] +} + +@test "is idempotent — running twice does not duplicate the row" { + bash "$HELPER" newskill "$FIX" + bash "$HELPER" newskill "$FIX" + count=$(grep -cE "^[[:space:]]*-[[:space:]]+skill:[[:space:]]+newskill[[:space:]]*$" "$FIX/docs/contracts/skill-dispositions.yaml") + [ "$count" -eq 1 ] +} + +@test "does not touch an already-present skill" { + run bash "$HELPER" existing "$FIX" + [ "$status" -eq 0 ] + count=$(grep -cE "^[[:space:]]*-[[:space:]]+skill:[[:space:]]+existing[[:space:]]*$" "$FIX/docs/contracts/skill-dispositions.yaml") + [ "$count" -eq 1 ] +}